Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -4,8 +4,10 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// platform includes
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
// lib includes
|
||||
#include "third-party/TPCircularBuffer/TPCircularBuffer.h"
|
||||
|
||||
#define kBufferLength 4096
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
* @file src/platform/macos/av_audio.m
|
||||
* @brief Definitions for audio capture on macOS.
|
||||
*/
|
||||
// local includes
|
||||
#import "av_audio.h"
|
||||
|
||||
@implementation AVAudio
|
||||
|
||||
+ (NSArray<AVCaptureDevice *> *)microphones {
|
||||
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:((NSOperatingSystemVersion) { 10, 15, 0 })]) {
|
||||
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:((NSOperatingSystemVersion) {10, 15, 0})]) {
|
||||
// This will generate a warning about AVCaptureDeviceDiscoverySession being
|
||||
// unavailable before macOS 10.15, but we have a guard to prevent it from
|
||||
// being called on those earlier systems.
|
||||
@@ -16,14 +17,12 @@
|
||||
// a different method.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
|
||||
AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInMicrophone,
|
||||
AVCaptureDeviceTypeExternalUnknown]
|
||||
AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInMicrophone, AVCaptureDeviceTypeExternalUnknown]
|
||||
mediaType:AVMediaTypeAudio
|
||||
position:AVCaptureDevicePositionUnspecified];
|
||||
return discoverySession.devices;
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// We're intentionally using a deprecated API here specifically for versions
|
||||
// of macOS where it's not deprecated, so we can ignore any deprecation
|
||||
// warnings:
|
||||
@@ -75,8 +74,7 @@
|
||||
|
||||
if ([self.audioCaptureSession canAddInput:audioInput]) {
|
||||
[self.audioCaptureSession addInput:audioInput];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
[audioInput dealloc];
|
||||
return -1;
|
||||
}
|
||||
@@ -92,17 +90,14 @@
|
||||
(NSString *) AVLinearPCMIsNonInterleaved: @NO
|
||||
}];
|
||||
|
||||
dispatch_queue_attr_t qos = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT,
|
||||
QOS_CLASS_USER_INITIATED,
|
||||
DISPATCH_QUEUE_PRIORITY_HIGH);
|
||||
dispatch_queue_attr_t qos = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_CONCURRENT, QOS_CLASS_USER_INITIATED, DISPATCH_QUEUE_PRIORITY_HIGH);
|
||||
dispatch_queue_t recordingQueue = dispatch_queue_create("audioSamplingQueue", qos);
|
||||
|
||||
[audioOutput setSampleBufferDelegate:self queue:recordingQueue];
|
||||
|
||||
if ([self.audioCaptureSession canAddOutput:audioOutput]) {
|
||||
[self.audioCaptureSession addOutput:audioOutput];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
[audioInput release];
|
||||
[audioOutput release];
|
||||
return -1;
|
||||
|
||||
@@ -4,17 +4,20 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "src/platform/common.h"
|
||||
|
||||
// platform includes
|
||||
#include <CoreMedia/CoreMedia.h>
|
||||
#include <CoreVideo/CoreVideo.h>
|
||||
|
||||
// local includes
|
||||
#include "src/platform/common.h"
|
||||
|
||||
namespace platf {
|
||||
struct av_sample_buf_t {
|
||||
CMSampleBufferRef buf;
|
||||
|
||||
explicit av_sample_buf_t(CMSampleBufferRef buf):
|
||||
buf((CMSampleBufferRef) CFRetain(buf)) {}
|
||||
buf((CMSampleBufferRef) CFRetain(buf)) {
|
||||
}
|
||||
|
||||
~av_sample_buf_t() {
|
||||
if (buf != nullptr) {
|
||||
@@ -29,12 +32,12 @@ namespace platf {
|
||||
// Constructor
|
||||
explicit av_pixel_buf_t(CMSampleBufferRef sb):
|
||||
buf(
|
||||
CMSampleBufferGetImageBuffer(sb)) {
|
||||
CMSampleBufferGetImageBuffer(sb)
|
||||
) {
|
||||
CVPixelBufferLockBaseAddress(buf, kCVPixelBufferLock_ReadOnly);
|
||||
}
|
||||
|
||||
[[nodiscard]] uint8_t *
|
||||
data() const {
|
||||
[[nodiscard]] uint8_t *data() const {
|
||||
return static_cast<uint8_t *>(CVPixelBufferGetBaseAddress(buf));
|
||||
}
|
||||
|
||||
@@ -59,8 +62,11 @@ namespace platf {
|
||||
temp_retain_av_img_t(
|
||||
std::shared_ptr<av_sample_buf_t> sb,
|
||||
std::shared_ptr<av_pixel_buf_t> pb,
|
||||
uint8_t *dt):
|
||||
uint8_t *dt
|
||||
):
|
||||
sample_buffer(std::move(sb)),
|
||||
pixel_buffer(std::move(pb)), data(dt) {}
|
||||
pixel_buffer(std::move(pb)),
|
||||
data(dt) {
|
||||
}
|
||||
};
|
||||
} // namespace platf
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
// platform includes
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
struct CaptureSession {
|
||||
AVCaptureVideoDataOutput *output;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* @file src/platform/macos/av_video.m
|
||||
* @brief Definitions for video capture on macOS.
|
||||
*/
|
||||
// local includes
|
||||
#import "av_video.h"
|
||||
|
||||
@implementation AVVideo
|
||||
@@ -62,8 +63,7 @@
|
||||
|
||||
if ([self.session canAddInput:screenInput]) {
|
||||
[self.session addInput:screenInput];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
[screenInput release];
|
||||
return nil;
|
||||
}
|
||||
@@ -97,9 +97,7 @@
|
||||
(NSString *) AVVideoScalingModeKey: AVVideoScalingModeResizeAspect,
|
||||
}];
|
||||
|
||||
dispatch_queue_attr_t qos = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
|
||||
QOS_CLASS_USER_INITIATED,
|
||||
DISPATCH_QUEUE_PRIORITY_HIGH);
|
||||
dispatch_queue_attr_t qos = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, DISPATCH_QUEUE_PRIORITY_HIGH);
|
||||
dispatch_queue_t recordingQueue = dispatch_queue_create("videoCaptureQueue", qos);
|
||||
[videoOutput setSampleBufferDelegate:self queue:recordingQueue];
|
||||
|
||||
@@ -107,8 +105,7 @@
|
||||
|
||||
if ([self.session canAddOutput:videoOutput]) {
|
||||
[self.session addOutput:videoOutput];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
[videoOutput release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
* @file src/platform/macos/display.mm
|
||||
* @brief Definitions for display capture on macOS.
|
||||
*/
|
||||
// local includes
|
||||
#include "src/config.h"
|
||||
#include "src/logging.h"
|
||||
#include "src/platform/common.h"
|
||||
#include "src/platform/macos/av_img_t.h"
|
||||
#include "src/platform/macos/av_video.h"
|
||||
#include "src/platform/macos/misc.h"
|
||||
#include "src/platform/macos/nv12_zero_device.h"
|
||||
|
||||
#include "src/config.h"
|
||||
#include "src/logging.h"
|
||||
|
||||
// Avoid conflict between AVFoundation and libavutil both defining AVMediaType
|
||||
#define AVMediaType AVMediaType_FFmpeg
|
||||
#include "src/video.h"
|
||||
@@ -29,8 +29,7 @@ namespace platf {
|
||||
[av_capture release];
|
||||
}
|
||||
|
||||
capture_e
|
||||
capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override {
|
||||
capture_e capture(const push_captured_image_cb_t &push_captured_image_cb, const pull_free_image_cb_t &pull_free_image_cb, bool *cursor) override {
|
||||
auto signal = [av_capture capture:^(CMSampleBufferRef sampleBuffer) {
|
||||
auto new_sample_buffer = std::make_shared<av_sample_buf_t>(sampleBuffer);
|
||||
auto new_pixel_buffer = std::make_shared<av_pixel_buf_t>(new_sample_buffer->buf);
|
||||
@@ -46,7 +45,8 @@ namespace platf {
|
||||
auto old_data_retainer = std::make_shared<temp_retain_av_img_t>(
|
||||
av_img->sample_buffer,
|
||||
av_img->pixel_buffer,
|
||||
img_out->data);
|
||||
img_out->data
|
||||
);
|
||||
|
||||
av_img->sample_buffer = new_sample_buffer;
|
||||
av_img->pixel_buffer = new_pixel_buffer;
|
||||
@@ -74,33 +74,28 @@ namespace platf {
|
||||
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::unique_ptr<avcodec_encode_device_t>
|
||||
make_avcodec_encode_device(pix_fmt_e pix_fmt) override {
|
||||
std::unique_ptr<avcodec_encode_device_t> make_avcodec_encode_device(pix_fmt_e pix_fmt) override {
|
||||
if (pix_fmt == pix_fmt_e::yuv420p) {
|
||||
av_capture.pixelFormat = kCVPixelFormatType_32BGRA;
|
||||
|
||||
return std::make_unique<avcodec_encode_device_t>();
|
||||
}
|
||||
else if (pix_fmt == pix_fmt_e::nv12 || pix_fmt == pix_fmt_e::p010) {
|
||||
} else if (pix_fmt == pix_fmt_e::nv12 || pix_fmt == pix_fmt_e::p010) {
|
||||
auto device = std::make_unique<nv12_zero_device>();
|
||||
|
||||
device->init(static_cast<void *>(av_capture), pix_fmt, setResolution, setPixelFormat);
|
||||
|
||||
return device;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
BOOST_LOG(error) << "Unsupported Pixel Format."sv;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dummy_img(img_t *img) override {
|
||||
int dummy_img(img_t *img) override {
|
||||
if (!platf::is_screen_capture_allowed()) {
|
||||
// If we don't have the screen capture permission, this function will hang
|
||||
// indefinitely without doing anything useful. Exit instead to avoid this.
|
||||
@@ -117,7 +112,8 @@ namespace platf {
|
||||
auto old_data_retainer = std::make_shared<temp_retain_av_img_t>(
|
||||
av_img->sample_buffer,
|
||||
av_img->pixel_buffer,
|
||||
img->data);
|
||||
img->data
|
||||
);
|
||||
|
||||
av_img->sample_buffer = new_sample_buffer;
|
||||
av_img->pixel_buffer = new_pixel_buffer;
|
||||
@@ -146,19 +142,16 @@ namespace platf {
|
||||
* 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 && hwdevice_type != platf::mem_type_e::videotoolbox) {
|
||||
BOOST_LOG(error) << "Could not initialize display with the given hw device type."sv;
|
||||
return nullptr;
|
||||
@@ -200,8 +193,7 @@ namespace platf {
|
||||
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];
|
||||
@@ -219,8 +211,7 @@ namespace platf {
|
||||
* @brief Returns if GPUs/drivers have changed since the last call to this function.
|
||||
* @return `true` if a change has occurred or if it is unknown whether a change occurred.
|
||||
*/
|
||||
bool
|
||||
needs_encoder_reenumeration() {
|
||||
bool needs_encoder_reenumeration() {
|
||||
// We don't track GPU state, so we will always reenumerate. Fortunately, it is fast on macOS.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,22 +2,24 @@
|
||||
* @file src/platform/macos/input.cpp
|
||||
* @brief Definitions for macOS input handling.
|
||||
*/
|
||||
#include "src/input.h"
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
// standard includes
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
// platform includes
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#import <Carbon/Carbon.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <mach/mach.h>
|
||||
|
||||
// local includes
|
||||
#include "src/display_device.h"
|
||||
#include "src/input.h"
|
||||
#include "src/logging.h"
|
||||
#include "src/platform/common.h"
|
||||
#include "src/utility.h"
|
||||
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
/**
|
||||
* @brief Delay for a double click, in milliseconds.
|
||||
* @todo Make this configurable.
|
||||
@@ -50,8 +52,7 @@ namespace platf {
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -227,13 +228,15 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
int
|
||||
keysym(int keycode) {
|
||||
int keysym(int keycode) {
|
||||
KeyCodeMap key_map {};
|
||||
|
||||
key_map.win_keycode = keycode;
|
||||
const KeyCodeMap *temp_map = std::lower_bound(
|
||||
kKeyCodesMap, kKeyCodesMap + sizeof(kKeyCodesMap) / sizeof(kKeyCodesMap[0]), key_map);
|
||||
kKeyCodesMap,
|
||||
kKeyCodesMap + sizeof(kKeyCodesMap) / sizeof(kKeyCodesMap[0]),
|
||||
key_map
|
||||
);
|
||||
|
||||
if (temp_map >= kKeyCodesMap + sizeof(kKeyCodesMap) / sizeof(kKeyCodesMap[0]) ||
|
||||
temp_map->win_keycode != keycode || temp_map->mac_keycode == -1) {
|
||||
@@ -243,8 +246,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
return temp_map->mac_keycode;
|
||||
}
|
||||
|
||||
void
|
||||
keyboard_update(input_t &input, uint16_t modcode, bool release, uint8_t flags) {
|
||||
void keyboard_update(input_t &input, uint16_t modcode, bool release, uint8_t flags) {
|
||||
auto key = keysym(modcode);
|
||||
|
||||
BOOST_LOG(debug) << "got keycode: 0x"sv << std::hex << modcode << ", translated to: 0x" << std::hex << key << ", release:" << release;
|
||||
@@ -284,8 +286,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
macos_input->kb_flags = release ? macos_input->kb_flags & ~mask : macos_input->kb_flags | mask;
|
||||
CGEventSetType(event, kCGEventFlagsChanged);
|
||||
CGEventSetFlags(event, macos_input->kb_flags);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
CGEventSetIntegerValueField(event, kCGKeyboardEventKeycode, key);
|
||||
CGEventSetType(event, release ? kCGEventKeyUp : kCGEventKeyDown);
|
||||
}
|
||||
@@ -293,30 +294,25 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
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, const gamepad_id_t &id, const gamepad_arrival_t &metadata, feedback_queue_t feedback_queue) {
|
||||
int alloc_gamepad(input_t &input, const gamepad_id_t &id, const gamepad_arrival_t &metadata, feedback_queue_t feedback_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_update(input_t &input, int nr, const gamepad_state_t &gamepad_state) {
|
||||
void gamepad_update(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:
|
||||
util::point_t
|
||||
get_mouse_loc(input_t &input) {
|
||||
util::point_t get_mouse_loc(input_t &input) {
|
||||
// Creating a new event every time to avoid any reuse risk
|
||||
const auto macos_input = static_cast<macos_input_t *>(input.get());
|
||||
const auto snapshot_event = CGEventCreate(macos_input->source);
|
||||
@@ -328,14 +324,14 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
};
|
||||
}
|
||||
|
||||
void
|
||||
post_mouse(
|
||||
void post_mouse(
|
||||
input_t &input,
|
||||
const CGMouseButton button,
|
||||
const CGEventType type,
|
||||
const util::point_t raw_location,
|
||||
const util::point_t previous_location,
|
||||
const int click_count) {
|
||||
const int click_count
|
||||
) {
|
||||
BOOST_LOG(debug) << "mouse_event: "sv << button << ", type: "sv << type << ", location:"sv << raw_location.x << ":"sv << raw_location.y << " click_count: "sv << click_count;
|
||||
|
||||
const auto macos_input = static_cast<macos_input_t *>(input.get());
|
||||
@@ -368,8 +364,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
CGWarpMouseCursorPosition(location);
|
||||
}
|
||||
|
||||
inline CGEventType
|
||||
event_type_mouse(input_t &input) {
|
||||
inline CGEventType event_type_mouse(input_t &input) {
|
||||
const auto macos_input = static_cast<macos_input_t *>(input.get());
|
||||
|
||||
if (macos_input->mouse_down[0]) {
|
||||
@@ -384,28 +379,28 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
return kCGEventMouseMoved;
|
||||
}
|
||||
|
||||
void
|
||||
move_mouse(
|
||||
void move_mouse(
|
||||
input_t &input,
|
||||
const int deltaX,
|
||||
const int deltaY) {
|
||||
const int deltaY
|
||||
) {
|
||||
const auto current = get_mouse_loc(input);
|
||||
|
||||
const auto location = util::point_t { current.x + deltaX, current.y + deltaY };
|
||||
const auto location = util::point_t {current.x + deltaX, current.y + deltaY};
|
||||
post_mouse(input, kCGMouseButtonLeft, event_type_mouse(input), location, current, 0);
|
||||
}
|
||||
|
||||
void
|
||||
abs_mouse(
|
||||
void abs_mouse(
|
||||
input_t &input,
|
||||
const touch_port_t &touch_port,
|
||||
const float x,
|
||||
const float y) {
|
||||
const float y
|
||||
) {
|
||||
const auto macos_input = static_cast<macos_input_t *>(input.get());
|
||||
const auto scaling = macos_input->displayScaling;
|
||||
const auto display = macos_input->display;
|
||||
|
||||
auto location = util::point_t { x * scaling, y * scaling };
|
||||
auto location = util::point_t {x * scaling, y * scaling};
|
||||
CGRect display_bounds = CGDisplayBounds(display);
|
||||
// in order to get the correct mouse location for capturing display , we need to add the display bounds to the location
|
||||
location.x += display_bounds.origin.x;
|
||||
@@ -414,8 +409,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
post_mouse(input, kCGMouseButtonLeft, event_type_mouse(input), location, get_mouse_loc(input), 0);
|
||||
}
|
||||
|
||||
void
|
||||
button_mouse(input_t &input, const int button, const bool release) {
|
||||
void button_mouse(input_t &input, const int button, const bool release) {
|
||||
CGMouseButton mac_button;
|
||||
CGEventType event;
|
||||
|
||||
@@ -447,26 +441,26 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
|
||||
if (now < macos_input->last_mouse_event[mac_button][release] + MULTICLICK_DELAY_MS) {
|
||||
post_mouse(input, mac_button, event, mouse_position, mouse_position, 2);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
post_mouse(input, mac_button, event, mouse_position, mouse_position, 1);
|
||||
}
|
||||
|
||||
macos_input->last_mouse_event[mac_button][release] = now;
|
||||
}
|
||||
|
||||
void
|
||||
scroll(input_t &input, const int high_res_distance) {
|
||||
void scroll(input_t &input, const int high_res_distance) {
|
||||
CGEventRef upEvent = CGEventCreateScrollWheelEvent(
|
||||
nullptr,
|
||||
kCGScrollEventUnitLine,
|
||||
2, high_res_distance > 0 ? 1 : -1, high_res_distance);
|
||||
2,
|
||||
high_res_distance > 0 ? 1 : -1,
|
||||
high_res_distance
|
||||
);
|
||||
CGEventPost(kCGHIDEventTap, upEvent);
|
||||
CFRelease(upEvent);
|
||||
}
|
||||
|
||||
void
|
||||
hscroll(input_t &input, int high_res_distance) {
|
||||
void hscroll(input_t &input, int high_res_distance) {
|
||||
// Unimplemented
|
||||
}
|
||||
|
||||
@@ -475,8 +469,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
* @param input The global input context.
|
||||
* @return A unique pointer to a per-client input data context.
|
||||
*/
|
||||
std::unique_ptr<client_input_t>
|
||||
allocate_client_input_context(input_t &input) {
|
||||
std::unique_ptr<client_input_t> allocate_client_input_context(input_t &input) {
|
||||
// Unused
|
||||
return nullptr;
|
||||
}
|
||||
@@ -487,8 +480,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
* @param touch_port The current viewport for translating to screen coordinates.
|
||||
* @param touch The touch event.
|
||||
*/
|
||||
void
|
||||
touch_update(client_input_t *input, const touch_port_t &touch_port, const touch_input_t &touch) {
|
||||
void touch_update(client_input_t *input, const touch_port_t &touch_port, const touch_input_t &touch) {
|
||||
// Unimplemented feature - platform_caps::pen_touch
|
||||
}
|
||||
|
||||
@@ -498,8 +490,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
* @param touch_port The current viewport for translating to screen coordinates.
|
||||
* @param pen The pen event.
|
||||
*/
|
||||
void
|
||||
pen_update(client_input_t *input, const touch_port_t &touch_port, const pen_input_t &pen) {
|
||||
void pen_update(client_input_t *input, const touch_port_t &touch_port, const pen_input_t &pen) {
|
||||
// Unimplemented feature - platform_caps::pen_touch
|
||||
}
|
||||
|
||||
@@ -508,8 +499,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
* @param input The global input context.
|
||||
* @param touch The touch event.
|
||||
*/
|
||||
void
|
||||
gamepad_touch(input_t &input, const gamepad_touch_t &touch) {
|
||||
void gamepad_touch(input_t &input, const gamepad_touch_t &touch) {
|
||||
// Unimplemented feature - platform_caps::controller_touch
|
||||
}
|
||||
|
||||
@@ -518,8 +508,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
* @param input The global input context.
|
||||
* @param motion The motion event.
|
||||
*/
|
||||
void
|
||||
gamepad_motion(input_t &input, const gamepad_motion_t &motion) {
|
||||
void gamepad_motion(input_t &input, const gamepad_motion_t &motion) {
|
||||
// Unimplemented
|
||||
}
|
||||
|
||||
@@ -528,14 +517,12 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
* @param input The global input context.
|
||||
* @param battery The battery event.
|
||||
*/
|
||||
void
|
||||
gamepad_battery(input_t &input, const gamepad_battery_t &battery) {
|
||||
void gamepad_battery(input_t &input, const gamepad_battery_t &battery) {
|
||||
// Unimplemented
|
||||
}
|
||||
|
||||
input_t
|
||||
input() {
|
||||
input_t result { new macos_input_t() };
|
||||
input_t input() {
|
||||
input_t result {new macos_input_t()};
|
||||
|
||||
const auto macos_input = static_cast<macos_input_t *>(result.get());
|
||||
|
||||
@@ -550,8 +537,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
CGDirectDisplayID displays[max_display];
|
||||
if (CGGetActiveDisplayList(max_display, displays, &display_count) != kCGErrorSuccess) {
|
||||
BOOST_LOG(error) << "Unable to get active display list , error: "sv << std::endl;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (int i = 0; i < display_count; i++) {
|
||||
CGDirectDisplayID display_id = displays[i];
|
||||
if (display_id == std::atoi(output_name.c_str())) {
|
||||
@@ -581,8 +567,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
freeInput(void *p) {
|
||||
void freeInput(void *p) {
|
||||
const auto *input = static_cast<macos_input_t *>(p);
|
||||
|
||||
CFRelease(input->source);
|
||||
@@ -592,10 +577,9 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
delete input;
|
||||
}
|
||||
|
||||
std::vector<supported_gamepad_t> &
|
||||
supported_gamepads(input_t *input) {
|
||||
std::vector<supported_gamepad_t> &supported_gamepads(input_t *input) {
|
||||
static std::vector gamepads {
|
||||
supported_gamepad_t { "", false, "gamepads.macos_not_implemented" }
|
||||
supported_gamepad_t {"", false, "gamepads.macos_not_implemented"}
|
||||
};
|
||||
|
||||
return gamepads;
|
||||
@@ -605,8 +589,7 @@ const KeyCodeMap kKeyCodesMap[] = {
|
||||
* @brief Returns the supported platform capabilities to advertise to the client.
|
||||
* @return Capability flags.
|
||||
*/
|
||||
platform_caps::caps_t
|
||||
get_capabilities() {
|
||||
platform_caps::caps_t get_capabilities() {
|
||||
return 0;
|
||||
}
|
||||
} // namespace platf
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
* @file src/platform/macos/microphone.mm
|
||||
* @brief Definitions for microphone capture on macOS.
|
||||
*/
|
||||
#include "src/platform/common.h"
|
||||
#include "src/platform/macos/av_audio.h"
|
||||
|
||||
// local includes
|
||||
#include "src/config.h"
|
||||
#include "src/logging.h"
|
||||
#include "src/platform/common.h"
|
||||
#include "src/platform/macos/av_audio.h"
|
||||
|
||||
namespace platf {
|
||||
using namespace std::literals;
|
||||
@@ -18,8 +18,7 @@ namespace platf {
|
||||
[av_audio_capture release];
|
||||
}
|
||||
|
||||
capture_e
|
||||
sample(std::vector<float> &sample_in) override {
|
||||
capture_e sample(std::vector<float> &sample_in) override {
|
||||
auto sample_size = sample_in.size();
|
||||
|
||||
uint32_t length = 0;
|
||||
@@ -45,14 +44,12 @@ namespace platf {
|
||||
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 = "";
|
||||
|
||||
@@ -81,22 +78,19 @@ namespace platf {
|
||||
return mic;
|
||||
}
|
||||
|
||||
bool
|
||||
is_sink_available(const std::string &sink) override {
|
||||
bool is_sink_available(const std::string &sink) override {
|
||||
BOOST_LOG(warning) << "audio_control_t::is_sink_available() unimplemented: "sv << sink;
|
||||
return true;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -4,21 +4,20 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// standard includes
|
||||
#include <vector>
|
||||
|
||||
// platform includes
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
namespace platf {
|
||||
bool
|
||||
is_screen_capture_allowed();
|
||||
bool is_screen_capture_allowed();
|
||||
}
|
||||
|
||||
namespace dyn {
|
||||
typedef void (*apiproc)();
|
||||
|
||||
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
|
||||
|
||||
@@ -8,24 +8,29 @@
|
||||
#define __APPLE_USE_RFC_3542 1
|
||||
#endif
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
// standard includes
|
||||
#include <fcntl.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
// platform includes
|
||||
#include <arpa/inet.h>
|
||||
#include <dlfcn.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <pwd.h>
|
||||
|
||||
// lib includes
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <boost/asio/ip/host_name.hpp>
|
||||
#include <boost/process/v1.hpp>
|
||||
|
||||
// local includes
|
||||
#include "misc.h"
|
||||
#include "src/entry_handler.h"
|
||||
#include "src/logging.h"
|
||||
#include "src/platform/common.h"
|
||||
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
#include <boost/asio/ip/host_name.hpp>
|
||||
#include <boost/process/v1.hpp>
|
||||
|
||||
using namespace std::literals;
|
||||
namespace fs = std::filesystem;
|
||||
namespace bp = boost::process;
|
||||
@@ -37,24 +42,20 @@ 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
|
||||
|
||||
namespace {
|
||||
auto screen_capture_allowed = std::atomic<bool> { false };
|
||||
auto screen_capture_allowed = std::atomic<bool> {false};
|
||||
} // namespace
|
||||
|
||||
// Return whether screen capture is allowed for this process.
|
||||
bool
|
||||
is_screen_capture_allowed() {
|
||||
bool is_screen_capture_allowed() {
|
||||
return screen_capture_allowed;
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -69,7 +70,7 @@ namespace platf {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
|
||||
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
|
||||
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:((NSOperatingSystemVersion) { 10, 15, 0 })] &&
|
||||
if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:((NSOperatingSystemVersion) {10, 15, 0})] &&
|
||||
// Double check that these weakly-linked symbols have been loaded:
|
||||
CGPreflightScreenCaptureAccess != nullptr && CGRequestScreenCaptureAccess != nullptr &&
|
||||
!CGPreflightScreenCaptureAccess()) {
|
||||
@@ -84,66 +85,55 @@ namespace platf {
|
||||
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;
|
||||
}
|
||||
|
||||
return fs::path { homedir } / ".config/sunshine"sv;
|
||||
return fs::path {homedir} / ".config/sunshine"sv;
|
||||
}
|
||||
|
||||
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
|
||||
|
||||
ifaddr_t
|
||||
get_ifaddrs() {
|
||||
ifaddrs *p { nullptr };
|
||||
ifaddr_t get_ifaddrs() {
|
||||
ifaddrs *p {nullptr};
|
||||
|
||||
getifaddrs(&p);
|
||||
|
||||
return ifaddr_t { p };
|
||||
return ifaddr_t {p};
|
||||
}
|
||||
|
||||
std::string
|
||||
from_sockaddr(const sockaddr *const ip_addr) {
|
||||
std::string from_sockaddr(const sockaddr *const ip_addr) {
|
||||
char data[INET6_ADDRSTRLEN] = {};
|
||||
|
||||
auto family = ip_addr->sa_family;
|
||||
if (family == AF_INET6) {
|
||||
inet_ntop(AF_INET6, &((sockaddr_in6 *) ip_addr)->sin6_addr, data,
|
||||
INET6_ADDRSTRLEN);
|
||||
}
|
||||
else if (family == AF_INET) {
|
||||
inet_ntop(AF_INET, &((sockaddr_in *) ip_addr)->sin_addr, data,
|
||||
INET_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &((sockaddr_in6 *) ip_addr)->sin6_addr, data, INET6_ADDRSTRLEN);
|
||||
} else if (family == AF_INET) {
|
||||
inet_ntop(AF_INET, &((sockaddr_in *) ip_addr)->sin_addr, data, INET_ADDRSTRLEN);
|
||||
}
|
||||
|
||||
return std::string { data };
|
||||
return std::string {data};
|
||||
}
|
||||
|
||||
std::pair<std::uint16_t, std::string>
|
||||
from_sockaddr_ex(const sockaddr *const ip_addr) {
|
||||
std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_addr) {
|
||||
char data[INET6_ADDRSTRLEN] = {};
|
||||
|
||||
auto family = ip_addr->sa_family;
|
||||
std::uint16_t port = 0;
|
||||
if (family == AF_INET6) {
|
||||
inet_ntop(AF_INET6, &((sockaddr_in6 *) ip_addr)->sin6_addr, data,
|
||||
INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &((sockaddr_in6 *) ip_addr)->sin6_addr, data, INET6_ADDRSTRLEN);
|
||||
port = ((sockaddr_in6 *) ip_addr)->sin6_port;
|
||||
}
|
||||
else if (family == AF_INET) {
|
||||
inet_ntop(AF_INET, &((sockaddr_in *) ip_addr)->sin_addr, data,
|
||||
INET_ADDRSTRLEN);
|
||||
} else if (family == AF_INET) {
|
||||
inet_ntop(AF_INET, &((sockaddr_in *) ip_addr)->sin_addr, data, INET_ADDRSTRLEN);
|
||||
port = ((sockaddr_in *) ip_addr)->sin_port;
|
||||
}
|
||||
|
||||
return { port, std::string { data } };
|
||||
return {port, std::string {data}};
|
||||
}
|
||||
|
||||
std::string
|
||||
get_mac_address(const std::string_view &address) {
|
||||
std::string get_mac_address(const std::string_view &address) {
|
||||
auto ifaddrs = get_ifaddrs();
|
||||
|
||||
for (auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
|
||||
@@ -160,8 +150,7 @@ namespace platf {
|
||||
ptr = (unsigned char *) LLADDR((struct sockaddr_dl *) (ifaptr)->ifa_addr);
|
||||
char buff[100];
|
||||
|
||||
snprintf(buff, sizeof(buff), "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
*ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4), *(ptr + 5));
|
||||
snprintf(buff, sizeof(buff), "%02x:%02x:%02x:%02x:%02x:%02x", *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3), *(ptr + 4), *(ptr + 5));
|
||||
mac_address = buff;
|
||||
break;
|
||||
}
|
||||
@@ -182,13 +171,11 @@ namespace platf {
|
||||
}
|
||||
|
||||
// TODO: return actual IP
|
||||
std::string
|
||||
get_local_ip_for_gateway() {
|
||||
std::string get_local_ip_for_gateway() {
|
||||
return "";
|
||||
}
|
||||
|
||||
bp::child
|
||||
run_command(bool elevated, bool interactive, const std::string &cmd, boost::filesystem::path &working_dir, const bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
|
||||
bp::child run_command(bool elevated, bool interactive, const std::string &cmd, boost::filesystem::path &working_dir, const bp::environment &env, FILE *file, std::error_code &ec, bp::group *group) {
|
||||
// clang-format off
|
||||
if (!group) {
|
||||
if (!file) {
|
||||
@@ -213,8 +200,7 @@ namespace platf {
|
||||
* @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;
|
||||
std::string cmd = R"(open ")" + url + R"(")";
|
||||
|
||||
@@ -223,30 +209,25 @@ namespace platf {
|
||||
auto child = run_command(false, false, cmd, working_dir, _env, nullptr, ec, nullptr);
|
||||
if (ec) {
|
||||
BOOST_LOG(warning) << "Couldn't open url ["sv << url << "]: System: "sv << ec.message();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
BOOST_LOG(info) << "Opened url ["sv << url << "]"sv;
|
||||
child.detach();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
void
|
||||
restart_on_exit() {
|
||||
void restart_on_exit() {
|
||||
char executable[2048];
|
||||
uint32_t size = sizeof(executable);
|
||||
if (_NSGetExecutablePath(executable, &size) < 0) {
|
||||
@@ -267,42 +248,35 @@ namespace platf {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
restart() {
|
||||
void restart() {
|
||||
// Gracefully clean up and restart ourselves instead of exiting
|
||||
atexit(restart_on_exit);
|
||||
lifetime::exit_sunshine(0, true);
|
||||
}
|
||||
|
||||
int
|
||||
set_env(const std::string &name, const std::string &value) {
|
||||
int set_env(const std::string &name, const std::string &value) {
|
||||
return setenv(name.c_str(), value.c_str(), 1);
|
||||
}
|
||||
|
||||
int
|
||||
unset_env(const std::string &name) {
|
||||
int unset_env(const std::string &name) {
|
||||
return unsetenv(name.c_str());
|
||||
}
|
||||
|
||||
bool
|
||||
request_process_group_exit(std::uintptr_t native_handle) {
|
||||
bool request_process_group_exit(std::uintptr_t native_handle) {
|
||||
if (killpg((pid_t) native_handle, SIGTERM) == 0 || errno == ESRCH) {
|
||||
BOOST_LOG(debug) << "Successfully sent SIGTERM to process group: "sv << native_handle;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
BOOST_LOG(warning) << "Unable to send SIGTERM to process group ["sv << native_handle << "]: "sv << errno;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
process_group_running(std::uintptr_t native_handle) {
|
||||
bool process_group_running(std::uintptr_t native_handle) {
|
||||
return waitpid(-((pid_t) native_handle), nullptr, WNOHANG) >= 0;
|
||||
}
|
||||
|
||||
struct sockaddr_in
|
||||
to_sockaddr(boost::asio::ip::address_v4 address, uint16_t port) {
|
||||
struct sockaddr_in to_sockaddr(boost::asio::ip::address_v4 address, uint16_t port) {
|
||||
struct sockaddr_in saddr_v4 = {};
|
||||
|
||||
saddr_v4.sin_family = AF_INET;
|
||||
@@ -314,8 +288,7 @@ namespace platf {
|
||||
return saddr_v4;
|
||||
}
|
||||
|
||||
struct sockaddr_in6
|
||||
to_sockaddr(boost::asio::ip::address_v6 address, uint16_t port) {
|
||||
struct sockaddr_in6 to_sockaddr(boost::asio::ip::address_v6 address, uint16_t port) {
|
||||
struct sockaddr_in6 saddr_v6 = {};
|
||||
|
||||
saddr_v6.sin6_family = AF_INET6;
|
||||
@@ -328,14 +301,12 @@ namespace platf {
|
||||
return saddr_v6;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool
|
||||
send(send_info_t &send_info) {
|
||||
bool send(send_info_t &send_info) {
|
||||
auto sockfd = (int) send_info.native_socket;
|
||||
struct msghdr msg = {};
|
||||
|
||||
@@ -347,8 +318,7 @@ namespace platf {
|
||||
|
||||
msg.msg_name = (struct sockaddr *) &taddr_v6;
|
||||
msg.msg_namelen = sizeof(taddr_v6);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
taddr_v4 = to_sockaddr(send_info.target_address.to_v4(), send_info.target_port);
|
||||
|
||||
msg.msg_name = (struct sockaddr *) &taddr_v4;
|
||||
@@ -359,6 +329,7 @@ namespace platf {
|
||||
char buf[std::max(CMSG_SPACE(sizeof(struct in_pktinfo)), CMSG_SPACE(sizeof(struct in6_pktinfo)))];
|
||||
struct cmsghdr alignment;
|
||||
} cmbuf {};
|
||||
|
||||
socklen_t cmbuflen = 0;
|
||||
|
||||
msg.msg_control = cmbuf.buf;
|
||||
@@ -378,8 +349,7 @@ namespace platf {
|
||||
pktinfo_cm->cmsg_type = IPV6_PKTINFO;
|
||||
pktinfo_cm->cmsg_len = CMSG_LEN(sizeof(pktInfo));
|
||||
memcpy(CMSG_DATA(pktinfo_cm), &pktInfo, sizeof(pktInfo));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
struct in_pktinfo pktInfo {};
|
||||
|
||||
struct sockaddr_in saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
|
||||
@@ -444,7 +414,8 @@ namespace platf {
|
||||
class qos_t: public deinit_t {
|
||||
public:
|
||||
qos_t(int sockfd, std::vector<std::tuple<int, int, int>> options):
|
||||
sockfd(sockfd), options(options) {
|
||||
sockfd(sockfd),
|
||||
options(options) {
|
||||
qos_ref_count++;
|
||||
}
|
||||
|
||||
@@ -472,8 +443,7 @@ namespace platf {
|
||||
* @param data_type The type of traffic sent on this socket.
|
||||
* @param dscp_tagging Specifies whether to enable DSCP tagging on outgoing traffic.
|
||||
*/
|
||||
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, bool dscp_tagging) {
|
||||
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, bool dscp_tagging) {
|
||||
int sockfd = (int) native_socket;
|
||||
std::vector<std::tuple<int, int, int>> reset_options;
|
||||
|
||||
@@ -495,8 +465,7 @@ namespace platf {
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_NET_SERVICE_TYPE, &service_type, sizeof(service_type)) == 0) {
|
||||
// Reset SO_NET_SERVICE_TYPE to best-effort when QoS is disabled
|
||||
reset_options.emplace_back(std::make_tuple(SOL_SOCKET, SO_NET_SERVICE_TYPE, NET_SERVICE_TYPE_BE));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
BOOST_LOG(error) << "Failed to set SO_NET_SERVICE_TYPE: "sv << errno;
|
||||
}
|
||||
}
|
||||
@@ -507,8 +476,7 @@ namespace platf {
|
||||
if (address.is_v6()) {
|
||||
level = IPPROTO_IPV6;
|
||||
option = IPV6_TCLASS;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
level = IPPROTO_IP;
|
||||
option = IP_TOS;
|
||||
}
|
||||
@@ -535,8 +503,7 @@ namespace platf {
|
||||
if (setsockopt(sockfd, level, option, &dscp, sizeof(dscp)) == 0) {
|
||||
// Reset TOS to -1 when QoS is disabled
|
||||
reset_options.emplace_back(std::make_tuple(level, option, -1));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
BOOST_LOG(error) << "Failed to set TOS/TCLASS: "sv << errno;
|
||||
}
|
||||
}
|
||||
@@ -545,12 +512,10 @@ namespace platf {
|
||||
return std::make_unique<qos_t>(sockfd, reset_options);
|
||||
}
|
||||
|
||||
std::string
|
||||
get_host_name() {
|
||||
std::string get_host_name() {
|
||||
try {
|
||||
return boost::asio::ip::host_name();
|
||||
}
|
||||
catch (boost::system::system_error &err) {
|
||||
} catch (boost::system::system_error &err) {
|
||||
BOOST_LOG(error) << "Failed to get hostname: "sv << err.what();
|
||||
return "Sunshine"s;
|
||||
}
|
||||
@@ -558,8 +523,7 @@ namespace platf {
|
||||
|
||||
class macos_high_precision_timer: public high_precision_timer {
|
||||
public:
|
||||
void
|
||||
sleep_for(const std::chrono::nanoseconds &duration) override {
|
||||
void sleep_for(const std::chrono::nanoseconds &duration) override {
|
||||
std::this_thread::sleep_for(duration);
|
||||
}
|
||||
|
||||
@@ -568,8 +532,7 @@ namespace platf {
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<high_precision_timer>
|
||||
create_high_precision_timer() {
|
||||
std::unique_ptr<high_precision_timer> create_high_precision_timer() {
|
||||
return std::make_unique<macos_high_precision_timer>();
|
||||
}
|
||||
|
||||
@@ -587,8 +550,7 @@ namespace platf {
|
||||
} // 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) {
|
||||
@@ -611,8 +573,7 @@ namespace dyn {
|
||||
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);
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
* @file src/platform/macos/nv12_zero_device.cpp
|
||||
* @brief Definitions for NV12 zero copy device on macOS.
|
||||
*/
|
||||
// standard includes
|
||||
#include <utility>
|
||||
|
||||
// local includes
|
||||
#include "src/platform/macos/av_img_t.h"
|
||||
#include "src/platform/macos/nv12_zero_device.h"
|
||||
|
||||
#include "src/video.h"
|
||||
|
||||
extern "C" {
|
||||
@@ -15,20 +16,17 @@ extern "C" {
|
||||
|
||||
namespace platf {
|
||||
|
||||
void
|
||||
free_frame(AVFrame *frame) {
|
||||
void free_frame(AVFrame *frame) {
|
||||
av_frame_free(&frame);
|
||||
}
|
||||
|
||||
void
|
||||
free_buffer(void *opaque, uint8_t *data) {
|
||||
void free_buffer(void *opaque, uint8_t *data) {
|
||||
CVPixelBufferRelease((CVPixelBufferRef) data);
|
||||
}
|
||||
|
||||
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) {
|
||||
auto *av_img = (av_img_t *) &img;
|
||||
|
||||
// Release any existing CVPixelBuffer previously retained for encoding
|
||||
@@ -47,8 +45,7 @@ namespace platf {
|
||||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -58,11 +55,8 @@ namespace platf {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
nv12_zero_device::init(void *display, pix_fmt_e pix_fmt, resolution_fn_t resolution_fn, const pixel_format_fn_t &pixel_format_fn) {
|
||||
pixel_format_fn(display, pix_fmt == pix_fmt_e::nv12 ?
|
||||
kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange :
|
||||
kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange);
|
||||
int nv12_zero_device::init(void *display, pix_fmt_e pix_fmt, resolution_fn_t resolution_fn, const pixel_format_fn_t &pixel_format_fn) {
|
||||
pixel_format_fn(display, pix_fmt == pix_fmt_e::nv12 ? kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange : kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange);
|
||||
|
||||
this->display = display;
|
||||
this->resolution_fn = std::move(resolution_fn);
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// local includes
|
||||
#include "src/platform/common.h"
|
||||
|
||||
struct AVFrame;
|
||||
|
||||
namespace platf {
|
||||
void
|
||||
free_frame(AVFrame *frame);
|
||||
void free_frame(AVFrame *frame);
|
||||
|
||||
class nv12_zero_device: public avcodec_encode_device_t {
|
||||
// display holds a pointer to an av_video object. Since the namespaces of AVFoundation
|
||||
@@ -24,13 +24,10 @@ namespace platf {
|
||||
resolution_fn_t resolution_fn;
|
||||
using pixel_format_fn_t = std::function<void(void *display, int pixelFormat)>;
|
||||
|
||||
int
|
||||
init(void *display, pix_fmt_e pix_fmt, resolution_fn_t resolution_fn, const pixel_format_fn_t &pixel_format_fn);
|
||||
int init(void *display, pix_fmt_e pix_fmt, resolution_fn_t resolution_fn, const pixel_format_fn_t &pixel_format_fn);
|
||||
|
||||
int
|
||||
convert(img_t &img) override;
|
||||
int
|
||||
set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) override;
|
||||
int convert(img_t &img) override;
|
||||
int set_frame(AVFrame *frame, AVBufferRef *hw_frames_ctx) override;
|
||||
|
||||
private:
|
||||
util::safe_ptr<AVFrame, free_frame> av_frame;
|
||||
|
||||
@@ -2,9 +2,13 @@
|
||||
* @file src/platform/macos/publish.cpp
|
||||
* @brief Definitions for publishing services on macOS.
|
||||
*/
|
||||
#include <dns_sd.h>
|
||||
// standard includes
|
||||
#include <thread>
|
||||
|
||||
// platform includes
|
||||
#include <dns_sd.h>
|
||||
|
||||
// local includes
|
||||
#include "src/logging.h"
|
||||
#include "src/network.h"
|
||||
#include "src/nvhttp.h"
|
||||
@@ -17,12 +21,13 @@ namespace platf::publish {
|
||||
/** @brief Custom deleter intended to be used for `std::unique_ptr<DNSServiceRef>`. */
|
||||
struct ServiceRefDeleter {
|
||||
typedef DNSServiceRef pointer; ///< Type of object to be deleted.
|
||||
void
|
||||
operator()(pointer serviceRef) {
|
||||
|
||||
void operator()(pointer serviceRef) {
|
||||
DNSServiceRefDeallocate(serviceRef);
|
||||
BOOST_LOG(info) << "Deregistered DNS service."sv;
|
||||
}
|
||||
};
|
||||
|
||||
/** @brief This class encapsulates the polling and deinitialization of our connection with
|
||||
* the mDNS service. Implements the `::platf::deinit_t` interface.
|
||||
*/
|
||||
@@ -37,25 +42,25 @@ namespace platf::publish {
|
||||
*/
|
||||
deinit_t(DNSServiceRef serviceRef):
|
||||
unique_ptr(serviceRef) {
|
||||
_thread = std::thread { [serviceRef, &_stopRequested = std::as_const(_stopRequested)]() {
|
||||
_thread = std::thread {[serviceRef, &_stopRequested = std::as_const(_stopRequested)]() {
|
||||
const auto socket = DNSServiceRefSockFD(serviceRef);
|
||||
while (!_stopRequested) {
|
||||
auto fdset = fd_set {};
|
||||
FD_ZERO(&fdset);
|
||||
FD_SET(socket, &fdset);
|
||||
auto timeout = timeval { .tv_sec = 3, .tv_usec = 0 }; // 3 second timeout
|
||||
auto timeout = timeval {.tv_sec = 3, .tv_usec = 0}; // 3 second timeout
|
||||
const auto ready = select(socket + 1, &fdset, nullptr, nullptr, &timeout);
|
||||
if (ready == -1) {
|
||||
BOOST_LOG(error) << "Failed to obtain response from DNS service."sv;
|
||||
break;
|
||||
}
|
||||
else if (ready != 0) {
|
||||
} else if (ready != 0) {
|
||||
DNSServiceProcessResult(serviceRef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} };
|
||||
}};
|
||||
}
|
||||
|
||||
/** @brief Ensure that we gracefully finish polling the mDNS service before freeing our
|
||||
* connection to it.
|
||||
*/
|
||||
@@ -63,9 +68,9 @@ namespace platf::publish {
|
||||
_stopRequested = true;
|
||||
_thread.join();
|
||||
}
|
||||
|
||||
deinit_t(const deinit_t &) = delete;
|
||||
deinit_t &
|
||||
operator=(const deinit_t &) = delete;
|
||||
deinit_t &operator=(const deinit_t &) = delete;
|
||||
|
||||
private:
|
||||
std::thread _thread; ///< Thread for polling the mDNS service for a response.
|
||||
@@ -75,10 +80,7 @@ namespace platf::publish {
|
||||
/** @brief Callback that will be invoked when the mDNS service finishes registering our service.
|
||||
* @param errorCode Describes whether the registration was successful.
|
||||
*/
|
||||
void
|
||||
registrationCallback(DNSServiceRef /*serviceRef*/, DNSServiceFlags /*flags*/,
|
||||
DNSServiceErrorType errorCode, const char * /*name*/,
|
||||
const char * /*regtype*/, const char * /*domain*/, void * /*context*/) {
|
||||
void registrationCallback(DNSServiceRef /*serviceRef*/, DNSServiceFlags /*flags*/, DNSServiceErrorType errorCode, const char * /*name*/, const char * /*regtype*/, const char * /*domain*/, void * /*context*/) {
|
||||
if (errorCode != kDNSServiceErr_NoError) {
|
||||
BOOST_LOG(error) << "Failed to register DNS service: Error "sv << errorCode;
|
||||
return;
|
||||
@@ -98,8 +100,7 @@ namespace platf::publish {
|
||||
* which will manage polling for a response from the mDNS service, and then, when
|
||||
* deconstructed, will deregister the service.
|
||||
*/
|
||||
[[nodiscard]] std::unique_ptr<::platf::deinit_t>
|
||||
start() {
|
||||
[[nodiscard]] std::unique_ptr<::platf::deinit_t> start() {
|
||||
auto serviceRef = DNSServiceRef {};
|
||||
const auto status = DNSServiceRegister(
|
||||
&serviceRef,
|
||||
|
||||
Reference in New Issue
Block a user