mirror of
https://github.com/LizardByte/Sunshine.git
synced 2024-11-18 11:10:04 +00:00
2b450839a1
This commit introduces initial support for MacOS as third major host platform. It relies on the VideoToolbox framework for audio and video processing, which enables hardware accelerated processing of the stream on most platforms. Audio capturing requires third party tools as MacOS does not offer the recording of the audio output like the other platforms do. The commit enables most features offered by Sunshine for MacOS with the big exception of gamepad support. The patch sets was tested by a few volunteers, which allowed to remove some of the early bugs. However, several bugs especially regarding corner cases have probably not surfaced yet. Besides instructions how to build from source, the commit also adds a Portfile that allows a more easy installation. After available on the release branch, a pull request for the Portfile in the MacPorts project is planned. Signed-off-by: Anselm Busse <anselm.busse@outlook.com>
88 lines
2.6 KiB
Plaintext
88 lines
2.6 KiB
Plaintext
#include "sunshine/platform/common.h"
|
|
#include "sunshine/platform/macos/av_audio.h"
|
|
|
|
#include "sunshine/config.h"
|
|
#include "sunshine/main.h"
|
|
|
|
namespace platf {
|
|
using namespace std::literals;
|
|
|
|
struct av_mic_t : public mic_t {
|
|
AVAudio *av_audio_capture;
|
|
|
|
~av_mic_t() {
|
|
[av_audio_capture release];
|
|
}
|
|
|
|
capture_e sample(std::vector<std::int16_t> &sample_in) override {
|
|
auto sample_size = sample_in.size();
|
|
|
|
uint32_t length = 0;
|
|
void *byteSampleBuffer = TPCircularBufferTail(&av_audio_capture->audioSampleBuffer, &length);
|
|
|
|
while(length < sample_size * sizeof(std::int16_t)) {
|
|
[av_audio_capture.samplesArrivedSignal wait];
|
|
byteSampleBuffer = TPCircularBufferTail(&av_audio_capture->audioSampleBuffer, &length);
|
|
}
|
|
|
|
const int16_t *sampleBuffer = (int16_t *)byteSampleBuffer;
|
|
std::vector<int16_t> vectorBuffer(sampleBuffer, sampleBuffer + sample_size);
|
|
|
|
std::copy_n(std::begin(vectorBuffer), sample_size, std::begin(sample_in));
|
|
|
|
TPCircularBufferConsume(&av_audio_capture->audioSampleBuffer, sample_size * sizeof(std::int16_t));
|
|
|
|
return capture_e::ok;
|
|
}
|
|
};
|
|
|
|
struct macos_audio_control_t : public audio_control_t {
|
|
AVCaptureDevice *audio_capture_device;
|
|
|
|
public:
|
|
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 {
|
|
auto mic = std::make_unique<av_mic_t>();
|
|
const char *audio_sink = "";
|
|
|
|
if(!config::audio.sink.empty()) {
|
|
audio_sink = config::audio.sink.c_str();
|
|
}
|
|
|
|
if((audio_capture_device = [AVAudio findMicrophone:[NSString stringWithUTF8String:audio_sink]]) == nullptr) {
|
|
BOOST_LOG(error) << "opening microphone '"sv << audio_sink << "' failed. Please set a valid input source in the Sunshine config."sv;
|
|
BOOST_LOG(error) << "Available inputs:"sv;
|
|
|
|
for(NSString *name in [AVAudio microphoneNames]) {
|
|
BOOST_LOG(error) << "\t"sv << [name UTF8String];
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
mic->av_audio_capture = [[AVAudio alloc] init];
|
|
|
|
if([mic->av_audio_capture setupMicrophone:audio_capture_device sampleRate:sample_rate frameSize:frame_size channels:channels]) {
|
|
BOOST_LOG(error) << "Failed to setup microphone."sv;
|
|
return nullptr;
|
|
}
|
|
|
|
return mic;
|
|
}
|
|
|
|
std::optional<sink_t> sink_info() override {
|
|
sink_t sink;
|
|
|
|
return sink;
|
|
}
|
|
};
|
|
|
|
std::unique_ptr<audio_control_t> audio_control() {
|
|
return std::make_unique<macos_audio_control_t>();
|
|
}
|
|
}
|