build parent process

This commit is contained in:
pigeatgarlic 2024-04-04 03:01:18 -07:00
parent 0f434e969d
commit 3f6c88419f
5 changed files with 388 additions and 11 deletions

View File

@ -3,17 +3,19 @@
add_executable(sunshine ${SUNSHINE_TARGET_FILES})
# Homebrew build fails the vite build if we set these environment variables
# this block must be before the platform specific code
if(${SUNSHINE_BUILD_HOMEBREW})
set(NPM_SOURCE_ASSETS_DIR "")
set(NPM_ASSETS_DIR "")
set(NPM_BUILD_HOMEBREW "true")
else()
set(NPM_SOURCE_ASSETS_DIR ${SUNSHINE_SOURCE_ASSETS_DIR})
set(NPM_ASSETS_DIR ${CMAKE_BINARY_DIR})
set(NPM_BUILD_HOMEBREW "")
endif()
add_executable(parent
"${CMAKE_SOURCE_DIR}/src/parent.cpp"
"${CMAKE_SOURCE_DIR}/src/interprocess.h"
"${CMAKE_SOURCE_DIR}/src/interprocess.cpp")
set_target_properties(parent PROPERTIES CXX_STANDARD 17)
target_link_libraries(parent
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES})
target_compile_options(parent PRIVATE ${SUNSHINE_COMPILE_OPTIONS})
# platform specific target definitions
if(WIN32)

189
src/interprocess.cpp Normal file
View File

@ -0,0 +1,189 @@
/**
* @file globals.cpp
* @brief Implementation for globally accessible variables and functions.
*/
#include "interprocess.h"
#include <thread>
#include <boost/interprocess/sync/scoped_lock.hpp>
using namespace boost::interprocess;
using namespace std::literals;
void
init_shared_memory(SharedMemory* memory){
for (int i = 0; i < QUEUE_SIZE; i++) {
memory->audio_order[i] = -1;
memory->video_order[i] = -1;
}
for (int i = 0; i < EventType::EVENT_TYPE_MAX; i++)
memory->events[i].read = 1;
}
int queue_size(int* queue) {
int i = 0;
while (*queue != -1 && i != QUEUE_SIZE){ // wait while queue is full
queue++;
i++;
}
return i;
}
void
push_audio_packet(SharedMemory* memory, void* data, int size){
// wait while queue is full
while (queue_size(memory->audio_order) == QUEUE_SIZE)
std::this_thread::sleep_for(1ms);
scoped_lock<interprocess_mutex> lock(memory->lock);
int available = -1;
// find available packet slot
for (int k = 0; k < QUEUE_SIZE; k++) {
int fnd = 0;
int j = 0;
while ( memory->audio_order[j] != -1 && j != QUEUE_SIZE) {
if (memory->audio_order[j] == k) {
fnd = 1;
break;
}
j++;
}
if (fnd)
continue;
available = k;
}
memory->audio_order[queue_size(memory->audio_order)] = available;
Packet* block = &memory->audio[available];
memcpy(block->data,data,size);
block->size = size;
}
void
push_video_packet(SharedMemory* memory,
void* data,
int size,
VideoMetadata metadata){
// wait while queue is full
while (queue_size(memory->audio_order) == QUEUE_SIZE)
std::this_thread::sleep_for(1ms);
scoped_lock<interprocess_mutex> lock(memory->lock);
int available = -1;
for (int k = 0; k < QUEUE_SIZE; k++) {
int fnd = 0;
int j = 0;
while ( memory->video_order[j] != -1 && j != QUEUE_SIZE) {
if (memory->video_order[j] == k) {
fnd = 1;
break;
}
j++;
}
if (fnd)
continue;
available = k;
}
memory->video_order[queue_size(memory->video_order)] = available;
Packet* block = &memory->video[available];
memcpy(block->data,data,size);
block->size = size;
block->metadata = metadata;
}
int
peek_video_packet(SharedMemory* memory){
return memory->video_order[0] != -1;
}
int
peek_audio_packet(SharedMemory* memory){
return memory->audio_order[0] != -1;
}
void
pop_audio_packet(SharedMemory* memory, void* data, int* size){
while (!peek_audio_packet(memory))
std::this_thread::sleep_for(1ms);
scoped_lock<interprocess_mutex> lock(memory->lock);
int pop = memory->audio_order[0];
Packet *block = &memory->audio[pop];
memcpy(data,block->data,block->size);
*size = block->size;
// reorder
for (int i = 0; i < QUEUE_SIZE - 1; i++)
memory->audio_order[i] = memory->audio_order[i+1];
memory->audio_order[QUEUE_SIZE - 1] = -1;
}
VideoMetadata
pop_video_packet(SharedMemory* memory, void* data, int* size){
while (!peek_video_packet(memory))
std::this_thread::sleep_for(1ms);
scoped_lock<interprocess_mutex> lock(memory->lock);
int pop = memory->video_order[0];
Packet *block = &memory->video[pop];
memcpy(data,block->data,block->size);
*size = block->size;
auto copy = block->metadata;
// reorder
for (int i = 0; i < QUEUE_SIZE - 1; i++)
memory->video_order[i] = memory->video_order[i+1];
memory->video_order[QUEUE_SIZE - 1] = -1;
return copy;
}
void
raise_event(SharedMemory* memory, EventType type, Event event){
event.read = false;
memcpy(&memory->events[type],&event,sizeof(Event));
}
int
peek_event(SharedMemory* memory, EventType type){
return !memory->events[type].read;
}
Event
pop_event(SharedMemory* memory, EventType type){
memory->events[type].read = true;
return memory->events[type];
}
void
wait_event(SharedMemory* memory, EventType type){
while(memory->events[type].read)
std::this_thread::sleep_for(1ms);
}

98
src/interprocess.h Normal file
View File

@ -0,0 +1,98 @@
/**
* @file globals.h
* @brief Header for globally accessible variables and functions.
*/
#pragma once
#include "thread_pool.h"
#include "thread_safe.h"
#include <boost/interprocess/sync/interprocess_mutex.hpp>
using namespace boost::interprocess;
#define QUEUE_SIZE 16
#define PACKET_SIZE 32 * 1024
typedef struct {
int is_idr;
}VideoMetadata;
typedef struct {
int size;
VideoMetadata metadata;
char data[PACKET_SIZE];
} Packet;
typedef enum _EventType {
POINTER_VISIBLE,
CHANGE_BITRATE,
CHANGE_FRAMERATE,
CHANGE_DISPLAY,
IDR_FRAME,
STOP,
HDR_CALLBACK,
EVENT_TYPE_MAX
} EventType;
typedef enum _DataType {
HDR_INFO,
} DataType;
typedef struct {
int value_number;
char value_raw[PACKET_SIZE];
int data_size;
DataType type;
int read;
} Event;
typedef struct {
interprocess_mutex lock;
Packet audio[QUEUE_SIZE];
Packet video[QUEUE_SIZE];
int audio_order[QUEUE_SIZE];
int video_order[QUEUE_SIZE];
Event events[EVENT_TYPE_MAX];
}SharedMemory;
void
init_shared_memory(SharedMemory* memory);
void
push_audio_packet(SharedMemory* memory, void* data, int size);
void
push_video_packet(SharedMemory* memory, void* data, int size, VideoMetadata metadata);
int
peek_video_packet(SharedMemory* memory);
int
peek_audio_packet(SharedMemory* memory);
void
pop_audio_packet(SharedMemory* memory, void* data, int* size);
VideoMetadata
pop_video_packet(SharedMemory* memory, void* data, int* size);
void
raise_event(SharedMemory* memory, EventType type, Event event);
int
peek_event(SharedMemory* memory, EventType type);
Event
pop_event(SharedMemory* memory, EventType type);
void
wait_event(SharedMemory* memory, EventType type);

View File

@ -7,9 +7,11 @@
#include <csignal>
#include <fstream>
#include <iostream>
#include <boost/interprocess/managed_shared_memory.hpp>
// local includes
#include "globals.h"
#include "interprocess.h"
#include "logging.h"
#include "main.h"
#include "version.h"
@ -23,6 +25,7 @@
#endif
using namespace std::literals;
using namespace boost::interprocess;
std::map<int, std::function<void()>> signal_handlers;
void
@ -142,6 +145,21 @@ main(int argc, char *argv[]) {
BOOST_LOG(error) << "Video failed to find working encoder"sv;
}
//Open managed segment
managed_shared_memory segment(open_only, "MySharedMemory");
//An handle from the base address can identify any byte of the shared
//memory segment even if it is mapped in different base addresses
managed_shared_memory::handle_t handle = 0;
//Obtain handle value
std::stringstream s; s << argv[1]; s >> handle;
//Get buffer local address from handle
SharedMemory* memory = (SharedMemory*)segment.get_address_from_handle(handle);
auto video_capture = std::thread{[&](){
video::capture(mail::man,video::config_t{
1920, 1080, 60, 6000, 1, 0, 1, 0, 0

70
src/parent.cpp Normal file
View File

@ -0,0 +1,70 @@
#include <boost/interprocess/managed_shared_memory.hpp>
#include <cstdlib> //std::system
#include <thread>
#include <sstream>
#include <iostream>
#include <thread>
#include "interprocess.h"
using namespace boost::interprocess;
using namespace std::literals;
int main (int argc, char *argv[]) {
//Remove shared memory on construction and destruction
struct shm_remove {
shm_remove() { shared_memory_object::remove("MySharedMemory"); }
~shm_remove(){ shared_memory_object::remove("MySharedMemory"); }
} remover;
//Create a managed shared memory segment
managed_shared_memory segment(create_only, "MySharedMemory", 2 * sizeof(SharedMemory));
//Allocate a portion of the segment (raw memory)
std::size_t free_memory = segment.get_free_memory();
SharedMemory* memory = (SharedMemory*)segment.allocate(sizeof(SharedMemory));
//Check invariant
if(free_memory <= segment.get_free_memory())
return 1;
auto running = true;
auto thread = std::thread{[&](){
while (running) {
// std::this_thread::sleep_for(1ms);
// if (!video_buffer->read) {
// std::cout << "Audio buffer received : " << video_buffer->size << "\n";
// video_buffer->read = true;
// }
// if (!audio_buffer->read) {
// std::cout << "Video buffer received : " << audio_buffer->size << "\n";
// audio_buffer->read = true;
// }
}
}};
//An handle from the base address can identify any byte of the shared
//memory segment even if it is mapped in different base addresses
managed_shared_memory::handle_t handle = segment.get_handle_from_address((void*)memory);
#ifdef _WIN32
auto binary = "sunshine.exe";
#else
auto binary = "./sunshine";
#endif
std::stringstream s; s << binary << " " << handle; s << std::ends;
//Launch child process
if(0 != std::system(s.str().c_str()))
return 1;
if(free_memory != segment.get_free_memory())
return 1;
running = false;
thread.join();
return 0;
}