mirror of
https://github.com/thinkonmay/sunshine-sdk.git
synced 2026-01-03 15:58:43 +00:00
capture audio and video in sunshine
This commit is contained in:
parent
baa0cc1e54
commit
fe9dbd3352
26
smemory.h
26
smemory.h
@ -1,4 +1,7 @@
|
||||
#define QUEUE_SIZE 64
|
||||
#define OUT_QUEUE_SIZE 8
|
||||
#define IN_QUEUE_SIZE 8
|
||||
|
||||
#define TAG_SIZE 8192
|
||||
#define PACKET_SIZE 5 * 1024 * 1024
|
||||
|
||||
typedef struct {
|
||||
@ -21,9 +24,20 @@ typedef struct {
|
||||
typedef struct _Queue{
|
||||
int inindex;
|
||||
int outindex;
|
||||
void* handle;
|
||||
QueueMetadata metadata;
|
||||
Packet incoming[IN_QUEUE_SIZE];
|
||||
Packet outgoing[OUT_QUEUE_SIZE];
|
||||
}Queue;
|
||||
|
||||
Packet incoming[QUEUE_SIZE];
|
||||
Packet outcoming[QUEUE_SIZE];
|
||||
}Queue;
|
||||
typedef struct _DisplayQueue{
|
||||
Queue internal;
|
||||
QueueMetadata metadata;
|
||||
}DisplayQueue;
|
||||
|
||||
typedef struct _Memory {
|
||||
DisplayQueue video;
|
||||
Queue audio;
|
||||
Queue data;
|
||||
|
||||
|
||||
char worker_info[TAG_SIZE];
|
||||
}Memory;
|
||||
@ -30,7 +30,6 @@ IVSHMEM::IVSHMEM() :
|
||||
m_initialized(false),
|
||||
m_handle(INVALID_HANDLE_VALUE),
|
||||
m_gotSize(false),
|
||||
m_gotPeerID(false),
|
||||
m_gotMemory(false)
|
||||
{
|
||||
|
||||
@ -112,7 +111,7 @@ void IVSHMEM::DeInitialize()
|
||||
if (m_gotMemory)
|
||||
{
|
||||
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_RELEASE_MMAP, NULL, 0, NULL, 0, NULL, NULL))
|
||||
printf("DeviceIoControl failed: %d", (int)GetLastError());
|
||||
printf("Deintialize DeviceIoControl failed: %d", (int)GetLastError());
|
||||
m_memory = NULL;
|
||||
}
|
||||
|
||||
@ -122,7 +121,6 @@ void IVSHMEM::DeInitialize()
|
||||
m_initialized = false;
|
||||
m_handle = INVALID_HANDLE_VALUE;
|
||||
m_gotSize = false;
|
||||
m_gotPeerID = false;
|
||||
m_gotMemory = false;
|
||||
}
|
||||
|
||||
@ -142,7 +140,7 @@ UINT64 IVSHMEM::GetSize()
|
||||
IVSHMEM_SIZE size;
|
||||
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &size, sizeof(IVSHMEM_SIZE), NULL, NULL))
|
||||
{
|
||||
printf("DeviceIoControl Failed: %d", (int)GetLastError());
|
||||
printf("GetSize DeviceIoControl Failed: %d", (int)GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -151,25 +149,7 @@ UINT64 IVSHMEM::GetSize()
|
||||
return m_size;
|
||||
}
|
||||
|
||||
UINT16 IVSHMEM::GetPeerID()
|
||||
{
|
||||
if (!m_initialized)
|
||||
return 0;
|
||||
|
||||
if (m_gotPeerID)
|
||||
return m_peerID;
|
||||
|
||||
IVSHMEM_PEERID peerID;
|
||||
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_REQUEST_SIZE, NULL, 0, &peerID, sizeof(IVSHMEM_PEERID), NULL, NULL))
|
||||
{
|
||||
printf("DeviceIoControl Failed: %d", (int)GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_gotPeerID = true;
|
||||
m_peerID = static_cast<UINT16>(peerID);
|
||||
return m_peerID;
|
||||
}
|
||||
|
||||
|
||||
void * IVSHMEM::GetMemory()
|
||||
@ -201,15 +181,13 @@ void * IVSHMEM::GetMemory()
|
||||
&map , sizeof(IVSHMEM_MMAP ),
|
||||
NULL, NULL))
|
||||
{
|
||||
printf("DeviceIoControl Failed: %d", (int)GetLastError());
|
||||
printf("GetMemory DeviceIoControl Failed: %d", (int)GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m_gotSize = true;
|
||||
m_gotPeerID = true;
|
||||
m_gotMemory = true;
|
||||
m_size = static_cast<UINT64>(map.size );
|
||||
m_peerID = static_cast<UINT16>(map.peerID );
|
||||
m_memory = map.ptr;
|
||||
|
||||
return m_memory;
|
||||
|
||||
@ -110,7 +110,6 @@ public:
|
||||
bool IsInitialized();
|
||||
|
||||
UINT64 GetSize();
|
||||
UINT16 GetPeerID();
|
||||
void * GetMemory();
|
||||
HANDLE getHandle();
|
||||
|
||||
@ -122,6 +121,5 @@ private:
|
||||
bool m_initialized;
|
||||
HANDLE m_handle;
|
||||
UINT64 m_size ; bool m_gotSize ;
|
||||
UINT16 m_peerID ; bool m_gotPeerID;
|
||||
void * m_memory ; bool m_gotMemory;
|
||||
};
|
||||
|
||||
206
src/main.cpp
206
src/main.cpp
@ -137,71 +137,64 @@ main(int argc, char *argv[]) {
|
||||
ivshmem->DeInitialize();
|
||||
});
|
||||
|
||||
int queuetype = QueueType::Video;
|
||||
std::stringstream ss0; ss0 << argv[1];
|
||||
std::string target; ss0 >> target;
|
||||
if (target == "audio")
|
||||
queuetype = QueueType::Audio;
|
||||
|
||||
int codec = 0;
|
||||
if (argc == 3) {
|
||||
std::stringstream ss1; ss1 << argv[2];
|
||||
std::string codecs; ss1 >> codecs;
|
||||
if (codecs == "h265")
|
||||
codec = 1;
|
||||
else if (codecs == "av1")
|
||||
codec = 2;
|
||||
}
|
||||
std::stringstream ss1; ss1 << argv[1];
|
||||
std::string codecs; ss1 >> codecs;
|
||||
if (codecs == "h265")
|
||||
codec = 1;
|
||||
else if (codecs == "av1")
|
||||
codec = 2;
|
||||
|
||||
|
||||
|
||||
if(queuetype == QueueType::Video) {
|
||||
#ifdef _WIN32
|
||||
// Modify relevant NVIDIA control panel settings if the system has corresponding gpu
|
||||
if (nvprefs_instance.load()) {
|
||||
// Restore global settings to the undo file left by improper termination of sunshine.exe
|
||||
nvprefs_instance.restore_from_and_delete_undo_file_if_exists();
|
||||
// Modify application settings for sunshine.exe
|
||||
nvprefs_instance.modify_application_profile();
|
||||
// Modify global settings, undo file is produced in the process to restore after improper termination
|
||||
nvprefs_instance.modify_global_profile();
|
||||
// Unload dynamic library to survive driver re-installation
|
||||
nvprefs_instance.unload();
|
||||
}
|
||||
|
||||
// Wait as long as possible to terminate Sunshine.exe during logoff/shutdown
|
||||
SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY);
|
||||
|
||||
// We must create a hidden window to receive shutdown notifications since we load gdi32.dll
|
||||
std::promise<HWND> session_monitor_hwnd_promise;
|
||||
auto session_monitor_hwnd_future = session_monitor_hwnd_promise.get_future();
|
||||
std::promise<void> session_monitor_join_thread_promise;
|
||||
auto session_monitor_join_thread_future = session_monitor_join_thread_promise.get_future();
|
||||
#endif
|
||||
// Modify relevant NVIDIA control panel settings if the system has corresponding gpu
|
||||
if (nvprefs_instance.load()) {
|
||||
// Restore global settings to the undo file left by improper termination of sunshine.exe
|
||||
nvprefs_instance.restore_from_and_delete_undo_file_if_exists();
|
||||
// Modify application settings for sunshine.exe
|
||||
nvprefs_instance.modify_application_profile();
|
||||
// Modify global settings, undo file is produced in the process to restore after improper termination
|
||||
nvprefs_instance.modify_global_profile();
|
||||
// Unload dynamic library to survive driver re-installation
|
||||
nvprefs_instance.unload();
|
||||
}
|
||||
|
||||
// Wait as long as possible to terminate Sunshine.exe during logoff/shutdown
|
||||
SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY);
|
||||
|
||||
// We must create a hidden window to receive shutdown notifications since we load gdi32.dll
|
||||
std::promise<HWND> session_monitor_hwnd_promise;
|
||||
auto session_monitor_hwnd_future = session_monitor_hwnd_promise.get_future();
|
||||
std::promise<void> session_monitor_join_thread_promise;
|
||||
auto session_monitor_join_thread_future = session_monitor_join_thread_promise.get_future();
|
||||
|
||||
|
||||
auto platf_deinit_guard = platf::init();
|
||||
|
||||
|
||||
if (ivshmem->GetSize() != (UINT64)sizeof(Queue)) {
|
||||
BOOST_LOG(error) << "Invalid ivshmem size: "sv << ivshmem->GetSize();
|
||||
Memory* memory = NULL;
|
||||
if (ivshmem->GetSize() < (UINT64)sizeof(Memory)) {
|
||||
BOOST_LOG(error) << "Invalid ivshmem size: "sv << ivshmem->GetSize();
|
||||
BOOST_LOG(error) << "Expected ivshmem size: "sv << sizeof(Memory);
|
||||
memory = (Memory*)malloc(sizeof(Memory));
|
||||
} else {
|
||||
BOOST_LOG(info) << "Found ivshmem shared memory"sv;
|
||||
memory = (Memory*)ivshmem->GetMemory();
|
||||
}
|
||||
|
||||
if (memory == NULL) {
|
||||
BOOST_LOG(error) << "Failed to allocate shared memory"sv;
|
||||
return StatusCode::INVALID_IVSHMEM;
|
||||
}
|
||||
|
||||
auto queue = (Queue*)ivshmem->GetMemory();
|
||||
if (!platf_deinit_guard) {
|
||||
BOOST_LOG(error) << "Platform failed to initialize"sv;
|
||||
return StatusCode::NO_ENCODER_AVAILABLE;
|
||||
} else if(queuetype == QueueType::Video && video::probe_encoders()) {
|
||||
} else if(video::probe_encoders()) {
|
||||
BOOST_LOG(error) << "Video failed to find working encoder"sv;
|
||||
return StatusCode::NO_ENCODER_AVAILABLE;
|
||||
} else if (queue == nullptr) {
|
||||
BOOST_LOG(error) << "Failed to find shared memory"sv;
|
||||
queue = (Queue*)malloc(sizeof(Queue));
|
||||
}
|
||||
|
||||
memset(queue,0,sizeof(Queue));
|
||||
auto video_capture = [&](safe::mail_t mail, std::string displayin,int codec){
|
||||
video::capture(mail,video::config_t{
|
||||
displayin, 1920, 1080, 60, 6000, 1, 0, 1, codec, 0
|
||||
@ -218,7 +211,7 @@ main(int argc, char *argv[]) {
|
||||
|
||||
auto mail = std::make_shared<safe::mail_raw_t>();
|
||||
|
||||
auto pull = [process_shutdown_event,queue,mail](){
|
||||
auto pull = [process_shutdown_event,mail](Queue* queue){
|
||||
auto timer = platf::create_high_precision_timer();
|
||||
auto local_shutdown= mail->event<bool>(mail::shutdown);
|
||||
auto bitrate = mail->event<int>(mail::bitrate);
|
||||
@ -233,12 +226,12 @@ main(int argc, char *argv[]) {
|
||||
timer->sleep_for(1ms);
|
||||
|
||||
memcpy(buffer,
|
||||
queue->outcoming[expected_index].data,
|
||||
queue->outcoming[expected_index].size
|
||||
queue->outgoing[expected_index].data,
|
||||
queue->outgoing[expected_index].size
|
||||
);
|
||||
|
||||
expected_index++;
|
||||
if (expected_index >= QUEUE_SIZE)
|
||||
if (expected_index >= OUT_QUEUE_SIZE)
|
||||
expected_index = 0;
|
||||
|
||||
switch (buffer[0]) {
|
||||
@ -281,7 +274,7 @@ main(int argc, char *argv[]) {
|
||||
};
|
||||
|
||||
|
||||
auto push = [process_shutdown_event](safe::mail_t mail, Queue* queue, QueueType queue_type){
|
||||
auto push_video = [process_shutdown_event](safe::mail_t mail, Queue* queue){
|
||||
auto video_packets = mail->queue<video::packet_t>(mail::video_packets);
|
||||
auto audio_packets = mail->queue<audio::packet_t>(mail::audio_packets);
|
||||
auto local_shutdown= mail->event<bool>(mail::shutdown);
|
||||
@ -294,54 +287,70 @@ main(int argc, char *argv[]) {
|
||||
|
||||
uint32_t findex = 0;
|
||||
while (!process_shutdown_event->peek() && !local_shutdown->peek()) {
|
||||
if (queue_type == QueueType::Video) {
|
||||
do {
|
||||
auto packet = video_packets->pop();
|
||||
char* ptr = (char*)packet->data();
|
||||
size_t size = packet->data_size();
|
||||
uint64_t utimestamp = packet->frame_timestamp.value().time_since_epoch().count();
|
||||
do {
|
||||
auto packet = video_packets->pop();
|
||||
char* ptr = (char*)packet->data();
|
||||
size_t size = packet->data_size();
|
||||
uint64_t utimestamp = packet->frame_timestamp.value().time_since_epoch().count();
|
||||
|
||||
auto updated = queue->inindex + 1;
|
||||
if (updated >= QUEUE_SIZE)
|
||||
updated = 0;
|
||||
auto updated = queue->inindex + 1;
|
||||
if (updated >= IN_QUEUE_SIZE)
|
||||
updated = 0;
|
||||
|
||||
findex++;
|
||||
uint16_t sum = 0;
|
||||
queue->incoming[updated].size = 0;
|
||||
copy_to_packet(&queue->incoming[updated],&findex,sizeof(uint32_t));
|
||||
copy_to_packet(&queue->incoming[updated],&utimestamp,sizeof(uint64_t));
|
||||
copy_to_packet(&queue->incoming[updated],&sum,sizeof(uint16_t));
|
||||
copy_to_packet(&queue->incoming[updated],ptr,size);
|
||||
queue->inindex = updated;
|
||||
} while (video_packets->peek());
|
||||
} else if (queue_type == QueueType::Audio) {
|
||||
do {
|
||||
auto packet = audio_packets->pop();
|
||||
char* ptr = (char*)packet->second.begin();
|
||||
size_t size = packet->second.size();
|
||||
uint64_t utimestamp = std::chrono::steady_clock::now().time_since_epoch().count();
|
||||
|
||||
auto updated = queue->inindex + 1;
|
||||
if (updated >= QUEUE_SIZE)
|
||||
updated = 0;
|
||||
|
||||
findex++;
|
||||
uint16_t sum = 0;
|
||||
queue->incoming[updated].size = 0;
|
||||
copy_to_packet(&queue->incoming[updated],&findex,sizeof(uint32_t));
|
||||
copy_to_packet(&queue->incoming[updated],&utimestamp,sizeof(uint64_t));
|
||||
copy_to_packet(&queue->incoming[updated],&sum,sizeof(uint16_t));
|
||||
copy_to_packet(&queue->incoming[updated],ptr,size);
|
||||
queue->inindex = updated;
|
||||
} while (audio_packets->peek());
|
||||
}
|
||||
findex++;
|
||||
uint16_t sum = 0;
|
||||
queue->incoming[updated].size = 0;
|
||||
copy_to_packet(&queue->incoming[updated],&findex,sizeof(uint32_t));
|
||||
copy_to_packet(&queue->incoming[updated],&utimestamp,sizeof(uint64_t));
|
||||
copy_to_packet(&queue->incoming[updated],&sum,sizeof(uint16_t));
|
||||
copy_to_packet(&queue->incoming[updated],ptr,size);
|
||||
queue->inindex = updated;
|
||||
} while (video_packets->peek());
|
||||
}
|
||||
|
||||
if (!local_shutdown->peek())
|
||||
local_shutdown->raise(true);
|
||||
};
|
||||
|
||||
auto touch_fun = [mail,process_shutdown_event](Queue* queue){
|
||||
auto push_audio = [process_shutdown_event](safe::mail_t mail, Queue* queue){
|
||||
auto video_packets = mail->queue<video::packet_t>(mail::video_packets);
|
||||
auto audio_packets = mail->queue<audio::packet_t>(mail::audio_packets);
|
||||
auto local_shutdown= mail->event<bool>(mail::shutdown);
|
||||
auto touch_port = mail->event<input::touch_port_t>(mail::touch_port);
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
platf::adjust_thread_priority(platf::thread_priority_e::critical);
|
||||
#endif
|
||||
|
||||
uint32_t findex = 0;
|
||||
while (!process_shutdown_event->peek() && !local_shutdown->peek()) {
|
||||
do {
|
||||
auto packet = audio_packets->pop();
|
||||
char* ptr = (char*)packet->second.begin();
|
||||
size_t size = packet->second.size();
|
||||
uint64_t utimestamp = std::chrono::steady_clock::now().time_since_epoch().count();
|
||||
|
||||
auto updated = queue->inindex + 1;
|
||||
if (updated >= IN_QUEUE_SIZE)
|
||||
updated = 0;
|
||||
|
||||
findex++;
|
||||
uint16_t sum = 0;
|
||||
queue->incoming[updated].size = 0;
|
||||
copy_to_packet(&queue->incoming[updated],&findex,sizeof(uint32_t));
|
||||
copy_to_packet(&queue->incoming[updated],&utimestamp,sizeof(uint64_t));
|
||||
copy_to_packet(&queue->incoming[updated],&sum,sizeof(uint16_t));
|
||||
copy_to_packet(&queue->incoming[updated],ptr,size);
|
||||
queue->inindex = updated;
|
||||
} while (audio_packets->peek());
|
||||
}
|
||||
|
||||
if (!local_shutdown->peek())
|
||||
local_shutdown->raise(true);
|
||||
};
|
||||
|
||||
auto touch_fun = [mail,process_shutdown_event](DisplayQueue* queue){
|
||||
auto timer = platf::create_high_precision_timer();
|
||||
auto local_shutdown= mail->event<bool>(mail::shutdown);
|
||||
auto touch_port = mail->event<input::touch_port_t>(mail::touch_port);
|
||||
@ -371,19 +380,20 @@ main(int argc, char *argv[]) {
|
||||
};
|
||||
|
||||
|
||||
BOOST_LOG(info) << "Starting capture on channel " << queuetype;
|
||||
if (queuetype == QueueType::Video) {
|
||||
auto capture = std::thread{video_capture,mail,target,codec};
|
||||
auto forward = std::thread{push,mail,queue,(QueueType)queuetype};
|
||||
auto touch_thread = std::thread{touch_fun,queue};
|
||||
auto receive = std::thread{pull};
|
||||
{
|
||||
auto capture = std::thread{video_capture,mail,"TODO",codec};
|
||||
auto forward = std::thread{push_video,mail,&memory->video.internal};
|
||||
auto touch_thread = std::thread{touch_fun,&memory->video};
|
||||
auto receive = std::thread{pull,&memory->video.internal};
|
||||
receive.detach();
|
||||
touch_thread.detach();
|
||||
capture.detach();
|
||||
forward.detach();
|
||||
} else if (queuetype == QueueType::Audio) {
|
||||
}
|
||||
|
||||
{
|
||||
auto capture = std::thread{audio_capture,mail};
|
||||
auto forward = std::thread{push,mail,queue,(QueueType)queuetype};
|
||||
auto forward = std::thread{push_audio,mail,&memory->audio};
|
||||
capture.detach();
|
||||
forward.detach();
|
||||
}
|
||||
|
||||
1
third-party/Simple-Web-Server
vendored
Submodule
1
third-party/Simple-Web-Server
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 187f798d54a9c6cee742f2eb2c54e9ba26f5a385
|
||||
1
third-party/ViGEmClient
vendored
Submodule
1
third-party/ViGEmClient
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 8d71f6740ffff4671cdadbca255ce528e3cd3fef
|
||||
1
third-party/doxyconfig
vendored
Submodule
1
third-party/doxyconfig
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit a73f908fb70fac4f6076a28f0a751239ea5ac2d3
|
||||
1
third-party/googletest
vendored
Submodule
1
third-party/googletest
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 52eb8108c5bdec04579160ae17225d66034bd723
|
||||
1
third-party/inputtino
vendored
Submodule
1
third-party/inputtino
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 83cf70ef33196a2a022671ccf8a686fc8f67ae8e
|
||||
1
third-party/libdisplaydevice
vendored
Submodule
1
third-party/libdisplaydevice
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit f31e46d8736fa6932d34c1417111e60ca507b29f
|
||||
1
third-party/moonlight-common-c
vendored
Submodule
1
third-party/moonlight-common-c
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 5f2280183cb62cba1052894d76e64e5f4153377d
|
||||
1
third-party/nanors
vendored
Submodule
1
third-party/nanors
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 19f07b513e924e471cadd141943c1ec4adc8d0e0
|
||||
1
third-party/tray
vendored
Submodule
1
third-party/tray
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 0309a7cb84aad25079b60c40d1eae0bacd05b26d
|
||||
Loading…
Reference in New Issue
Block a user