mirror of
https://github.com/Lorenzooone/cc3dsfs.git
synced 2025-06-18 16:45:39 -04:00
602 lines
22 KiB
C++
Executable File
602 lines
22 KiB
C++
Executable File
#include <SFML/Audio.hpp>
|
|
#include <SFML/Graphics.hpp>
|
|
|
|
#if (!defined(_MSC_VER)) || (_MSC_VER > 1916)
|
|
#include <filesystem>
|
|
#else
|
|
#include <experimental/filesystem>
|
|
#endif
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <cstring>
|
|
#include <thread>
|
|
#include <mutex>
|
|
#include <chrono>
|
|
#include <queue>
|
|
|
|
#include "utils.hpp"
|
|
#include "devicecapture.hpp"
|
|
#include "hw_defs.hpp"
|
|
#include "frontend.hpp"
|
|
#include "audio.hpp"
|
|
#include "conversions.hpp"
|
|
|
|
// Threshold to keep the audio latency limited in "amount of frames".
|
|
#define NUM_CONCURRENT_AUDIO_BUFFERS ((MAX_MAX_AUDIO_LATENCY * 2) + 1)
|
|
|
|
#define LOW_POLL_DIVISOR 6
|
|
#define NO_DATA_CONSECUTIVE_THRESHOLD 4
|
|
|
|
struct OutTextData {
|
|
std::string full_text;
|
|
std::string small_text;
|
|
bool consumed;
|
|
TextKind kind;
|
|
};
|
|
|
|
static void ConsoleOutText(std::string full_text) {
|
|
if(full_text != "")
|
|
std::cout << "[" << NAME << "] " << full_text << std::endl;
|
|
}
|
|
|
|
static void UpdateOutText(OutTextData &out_text_data, std::string full_text, std::string small_text, TextKind kind) {
|
|
if(!out_text_data.consumed)
|
|
ConsoleOutText(out_text_data.full_text);
|
|
out_text_data.full_text = full_text;
|
|
out_text_data.small_text = small_text;
|
|
out_text_data.kind = kind;
|
|
out_text_data.consumed = false;
|
|
}
|
|
|
|
static void SuccessConnectionOutTextGenerator(OutTextData &out_text_data, CaptureData* capture_data) {
|
|
if(capture_data->status.connected)
|
|
UpdateOutText(out_text_data, "Connected to " + capture_data->status.device.name + " - " + capture_data->status.device.serial_number, "Connected", TEXT_KIND_SUCCESS);
|
|
else if(!capture_data->status.new_error_text) {
|
|
UpdateOutText(out_text_data, "Disconnected", "Disconnected", TEXT_KIND_WARNING);
|
|
}
|
|
}
|
|
|
|
static bool load(const std::string path, const std::string name, ScreenInfo &top_info, ScreenInfo &bottom_info, ScreenInfo &joint_info, DisplayData &display_data, AudioData *audio_data, OutTextData &out_text_data, ExtraButtonShortcuts* extra_button_shortcuts, CaptureStatus* capture_status) {
|
|
std::ifstream file(path + name);
|
|
std::string line;
|
|
|
|
if((!file) || (!file.is_open()) || (!file.good())) {
|
|
UpdateOutText(out_text_data, "File " + path + name + " load failed.\nDefaults re-loaded.", "Load failed\nDefaults re-loaded", TEXT_KIND_ERROR);
|
|
return false;
|
|
}
|
|
|
|
bool result = true;
|
|
|
|
try {
|
|
while(std::getline(file, line)) {
|
|
std::istringstream kvp(line);
|
|
std::string key;
|
|
|
|
if(std::getline(kvp, key, '=')) {
|
|
std::string value;
|
|
|
|
if(std::getline(kvp, value)) {
|
|
|
|
if(load_screen_info(key, value, "bot_", bottom_info))
|
|
continue;
|
|
if(load_screen_info(key, value, "joint_", joint_info))
|
|
continue;
|
|
if(load_screen_info(key, value, "top_", top_info))
|
|
continue;
|
|
|
|
if(key == "split") {
|
|
display_data.split = std::stoi(value);
|
|
continue;
|
|
}
|
|
|
|
if(key == "fast_poll") {
|
|
display_data.fast_poll = std::stoi(value);
|
|
continue;
|
|
}
|
|
|
|
if(key == "last_connected_ds") {
|
|
display_data.last_connected_ds = std::stoi(value);
|
|
continue;
|
|
}
|
|
|
|
if(key == "extra_button_enter_short") {
|
|
extra_button_shortcuts->enter_shortcut = get_window_command(static_cast<PossibleWindowCommands>(std::stoi(value)));
|
|
continue;
|
|
}
|
|
|
|
if(key == "extra_button_page_up_short") {
|
|
extra_button_shortcuts->page_up_shortcut = get_window_command(static_cast<PossibleWindowCommands>(std::stoi(value)));
|
|
continue;
|
|
}
|
|
|
|
if(key == "is_screen_capture_type") {
|
|
capture_status->capture_type = static_cast<CaptureScreensType>(std::stoi(value) % CaptureScreensType::CAPTURE_SCREENS_ENUM_END);
|
|
continue;
|
|
}
|
|
|
|
if(key == "is_speed_capture") {
|
|
capture_status->capture_speed = static_cast<CaptureSpeedsType>(std::stoi(value) % CaptureSpeedsType::CAPTURE_SPEEDS_ENUM_END);
|
|
continue;
|
|
}
|
|
|
|
if(audio_data->load_audio_data(key, value))
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch(...) {
|
|
UpdateOutText(out_text_data, "File " + path + name + " load failed.\nDefaults re-loaded.", "Load failed\nDefaults re-loaded", TEXT_KIND_ERROR);
|
|
result = false;
|
|
}
|
|
|
|
file.close();
|
|
return result;
|
|
}
|
|
|
|
static void defaults_reload(FrontendData *frontend_data, AudioData* audio_data, ExtraButtonShortcuts* extra_button_shortcuts, CaptureStatus* capture_status) {
|
|
capture_status->enabled_3d = false;
|
|
capture_status->capture_type = CAPTURE_SCREENS_BOTH;
|
|
capture_status->capture_speed = CAPTURE_SPEEDS_FULL;
|
|
reset_screen_info(frontend_data->top_screen->m_info);
|
|
reset_screen_info(frontend_data->bot_screen->m_info);
|
|
reset_screen_info(frontend_data->joint_screen->m_info);
|
|
audio_data->reset();
|
|
extra_button_shortcuts->enter_shortcut = get_window_command(WINDOW_COMMAND_RATIO_CYCLE);
|
|
extra_button_shortcuts->page_up_shortcut = get_window_command(WINDOW_COMMAND_CROP);
|
|
reset_display_data(&frontend_data->display_data);
|
|
if(frontend_data->display_data.mono_app_mode)
|
|
frontend_data->joint_screen->m_info.is_fullscreen = true;
|
|
frontend_data->reload = true;
|
|
}
|
|
|
|
static void load_layout_file(int load_index, FrontendData *frontend_data, AudioData* audio_data, OutTextData &out_text_data, ExtraButtonShortcuts* extra_button_shortcuts, CaptureStatus* capture_status, bool skip_io, bool do_print, bool created_proper_folder) {
|
|
if(skip_io)
|
|
return;
|
|
|
|
defaults_reload(frontend_data, audio_data, extra_button_shortcuts, capture_status);
|
|
|
|
if(load_index == SIMPLE_RESET_DATA_INDEX) {
|
|
UpdateOutText(out_text_data, "Reset detected. Defaults re-loaded", "Reset detected\nDefaults re-loaded", TEXT_KIND_WARNING);
|
|
return;
|
|
}
|
|
|
|
bool name_load_success = false;
|
|
std::string layout_name = LayoutNameGenerator(load_index);
|
|
std::string layout_path = LayoutPathGenerator(load_index, created_proper_folder);
|
|
bool op_success = load(layout_path, layout_name, frontend_data->top_screen->m_info, frontend_data->bot_screen->m_info, frontend_data->joint_screen->m_info, frontend_data->display_data, audio_data, out_text_data, extra_button_shortcuts, capture_status);
|
|
if(do_print && op_success) {
|
|
std::string load_name = load_layout_name(load_index, created_proper_folder, name_load_success);
|
|
UpdateOutText(out_text_data, "Layout loaded from: " + layout_path + layout_name, "Layout " + load_name + " loaded", TEXT_KIND_SUCCESS);
|
|
}
|
|
else if(!op_success)
|
|
defaults_reload(frontend_data, audio_data, extra_button_shortcuts, capture_status);
|
|
}
|
|
|
|
static bool save(const std::string path, const std::string name, const std::string save_name, const ScreenInfo &top_info, const ScreenInfo &bottom_info, const ScreenInfo &joint_info, DisplayData &display_data, AudioData *audio_data, OutTextData &out_text_data, ExtraButtonShortcuts* extra_button_shortcuts, CaptureStatus* capture_status) {
|
|
std::ofstream file(path + name);
|
|
if(!file.good()) {
|
|
UpdateOutText(out_text_data, "File " + path + name + " save failed.", "Save failed", TEXT_KIND_ERROR);
|
|
return false;
|
|
}
|
|
|
|
file << "name=" << save_name << std::endl;
|
|
file << "version=" << get_version_string(false) << std::endl;
|
|
file << save_screen_info("bot_", bottom_info);
|
|
file << save_screen_info("joint_", joint_info);
|
|
file << save_screen_info("top_", top_info);
|
|
file << "split=" << display_data.split << std::endl;
|
|
file << "fast_poll=" << display_data.fast_poll << std::endl;
|
|
file << "last_connected_ds=" << display_data.last_connected_ds << std::endl;
|
|
file << "extra_button_enter_short=" << extra_button_shortcuts->enter_shortcut->cmd << std::endl;
|
|
file << "extra_button_page_up_short=" << extra_button_shortcuts->page_up_shortcut->cmd << std::endl;
|
|
file << "is_screen_capture_type=" << capture_status->capture_type << std::endl;
|
|
file << "is_speed_capture=" << capture_status->capture_speed << std::endl;
|
|
file << audio_data->save_audio_data();
|
|
|
|
file.close();
|
|
return true;
|
|
}
|
|
|
|
static void save_layout_file(int save_index, FrontendData *frontend_data, AudioData* audio_data, OutTextData &out_text_data, ExtraButtonShortcuts* extra_button_shortcuts, CaptureStatus* capture_status, bool skip_io, bool do_print, bool created_proper_folder) {
|
|
if(skip_io)
|
|
return;
|
|
|
|
if(save_index == SIMPLE_RESET_DATA_INDEX)
|
|
return;
|
|
|
|
bool name_load_success = false;
|
|
std::string save_name = load_layout_name(save_index, created_proper_folder, name_load_success);
|
|
std::string layout_name = LayoutNameGenerator(save_index);
|
|
std::string layout_path = LayoutPathGenerator(save_index, created_proper_folder);
|
|
bool op_success = save(layout_path, layout_name, save_name, frontend_data->top_screen->m_info, frontend_data->bot_screen->m_info, frontend_data->joint_screen->m_info, frontend_data->display_data, audio_data, out_text_data, extra_button_shortcuts, capture_status);
|
|
if(do_print && op_success) {
|
|
UpdateOutText(out_text_data, "Layout saved to: " + layout_path + layout_name, "Layout " + save_name + " saved", TEXT_KIND_SUCCESS);
|
|
}
|
|
}
|
|
|
|
static void executeSoundRestart(Audio &audio, AudioData* audio_data, bool do_restart) {
|
|
if(do_restart) {
|
|
audio.stop();
|
|
audio.~Audio();
|
|
::new(&audio) Audio(audio_data);
|
|
}
|
|
audio.start_audio();
|
|
audio.play();
|
|
}
|
|
|
|
static void soundCall(AudioData *audio_data, CaptureData* capture_data) {
|
|
std::int16_t (*out_buf)[MAX_SAMPLES_IN] = new std::int16_t[NUM_CONCURRENT_AUDIO_BUFFERS][MAX_SAMPLES_IN];
|
|
Audio audio(audio_data);
|
|
int audio_buf_counter = 0;
|
|
const bool endianness = is_big_endian();
|
|
volatile int loaded_samples;
|
|
|
|
while(capture_data->status.running) {
|
|
if(capture_data->status.connected && capture_data->status.device.has_audio) {
|
|
bool timed_out = !capture_data->status.audio_wait.timed_lock();
|
|
|
|
if(!capture_data->status.cooldown_curr_in) {
|
|
CaptureDataSingleBuffer* data_buffer = capture_data->data_buffers.GetReaderBuffer(CAPTURE_READER_AUDIO);
|
|
if(data_buffer != NULL) {
|
|
loaded_samples = audio.samples.size();
|
|
if((data_buffer->read > get_video_in_size(capture_data)) && (loaded_samples < MAX_MAX_AUDIO_LATENCY)) {
|
|
uint64_t n_samples = get_audio_n_samples(capture_data, data_buffer->read);
|
|
double out_time = data_buffer->time_in_buf;
|
|
bool conversion_success = convertAudioToOutput(out_buf[audio_buf_counter], n_samples, endianness, data_buffer, &capture_data->status);
|
|
if(!conversion_success)
|
|
audio_data->signal_conversion_error();
|
|
audio.samples.emplace(out_buf[audio_buf_counter], n_samples, out_time);
|
|
if(++audio_buf_counter >= NUM_CONCURRENT_AUDIO_BUFFERS)
|
|
audio_buf_counter = 0;
|
|
audio.samples_wait.unlock();
|
|
}
|
|
capture_data->data_buffers.ReleaseReaderBuffer(CAPTURE_READER_AUDIO);
|
|
}
|
|
}
|
|
|
|
loaded_samples = audio.samples.size();
|
|
if(audio.getStatus() != sf::SoundStream::Status::Playing) {
|
|
audio.stop_audio();
|
|
if(loaded_samples > 0)
|
|
executeSoundRestart(audio, audio_data, audio.restart);
|
|
}
|
|
else {
|
|
if(loaded_samples > 0) {
|
|
if(audio.hasTooMuchTimeElapsed()) {
|
|
audio.stop_audio();
|
|
executeSoundRestart(audio, audio_data, true);
|
|
}
|
|
}
|
|
audio.update_volume();
|
|
}
|
|
}
|
|
else {
|
|
audio.stop_audio();
|
|
audio.stop();
|
|
default_sleep();
|
|
}
|
|
}
|
|
|
|
audio.stop_audio();
|
|
audio.stop();
|
|
delete []out_buf;
|
|
}
|
|
|
|
static void poll_all_windows(FrontendData *frontend_data, bool do_everything, bool &polled) {
|
|
if(!polled) {
|
|
frontend_data->top_screen->poll(do_everything);
|
|
frontend_data->bot_screen->poll(do_everything);
|
|
frontend_data->joint_screen->poll(do_everything);
|
|
polled = true;
|
|
}
|
|
}
|
|
|
|
static void check_close_application(WindowScreen *screen, CaptureData* capture_data, int &ret_val) {
|
|
if(screen->close_capture() && capture_data->status.running) {
|
|
capture_data->status.running = false;
|
|
ret_val = screen->get_ret_val();
|
|
}
|
|
}
|
|
|
|
static float get_time_multiplier(CaptureData* capture_data, bool should_ignore_data_rate) {
|
|
if(should_ignore_data_rate)
|
|
return 1.0;
|
|
if(capture_data->status.device.cc_type != CAPTURE_CONN_IS_NITRO)
|
|
return 1.0;
|
|
switch(capture_data->status.capture_speed) {
|
|
case CAPTURE_SPEEDS_HALF:
|
|
return 2.0;
|
|
case CAPTURE_SPEEDS_THIRD:
|
|
return 3.0;
|
|
case CAPTURE_SPEEDS_QUARTER:
|
|
return 4.0;
|
|
default:
|
|
return 1.0;
|
|
}
|
|
}
|
|
|
|
static int mainVideoOutputCall(AudioData* audio_data, CaptureData* capture_data, bool mono_app, bool created_proper_folder) {
|
|
VideoOutputData *out_buf;
|
|
double last_frame_time = 0.0;
|
|
int num_elements_fps_array = 0;
|
|
FrontendData frontend_data;
|
|
ConsumerMutex draw_lock;
|
|
reset_display_data(&frontend_data.display_data);
|
|
frontend_data.display_data.mono_app_mode = mono_app;
|
|
frontend_data.reload = true;
|
|
bool skip_io = false;
|
|
int num_allowed_blanks = MAX_ALLOWED_BLANKS;
|
|
OutTextData out_text_data;
|
|
ExtraButtonShortcuts extra_button_shortcuts;
|
|
out_text_data.consumed = true;
|
|
int ret_val = 0;
|
|
int poll_timeout = 0;
|
|
const bool endianness = is_big_endian();
|
|
|
|
out_buf = new VideoOutputData;
|
|
memset(out_buf, 0, sizeof(VideoOutputData));
|
|
|
|
draw_lock.unlock();
|
|
WindowScreen *top_screen = new WindowScreen(ScreenType::TOP, &capture_data->status, &frontend_data.display_data, audio_data, &extra_button_shortcuts, &draw_lock, created_proper_folder);
|
|
WindowScreen *bot_screen = new WindowScreen(ScreenType::BOTTOM, &capture_data->status, &frontend_data.display_data, audio_data, &extra_button_shortcuts, &draw_lock, created_proper_folder);
|
|
WindowScreen *joint_screen = new WindowScreen(ScreenType::JOINT, &capture_data->status, &frontend_data.display_data, audio_data, &extra_button_shortcuts, &draw_lock, created_proper_folder);
|
|
frontend_data.top_screen = top_screen;
|
|
frontend_data.bot_screen = bot_screen;
|
|
frontend_data.joint_screen = joint_screen;
|
|
|
|
load_layout_file(STARTUP_FILE_INDEX, &frontend_data, audio_data, out_text_data, &extra_button_shortcuts, &capture_data->status, skip_io, false, created_proper_folder);
|
|
// Due to the risk for seizures, at the start of the program, set BFI to false!
|
|
top_screen->m_info.bfi = false;
|
|
bot_screen->m_info.bfi = false;
|
|
joint_screen->m_info.bfi = false;
|
|
|
|
top_screen->build();
|
|
bot_screen->build();
|
|
joint_screen->build();
|
|
|
|
std::thread top_thread(screen_display_thread, top_screen);
|
|
std::thread bot_thread(screen_display_thread, bot_screen);
|
|
std::thread joint_thread(screen_display_thread, joint_screen);
|
|
|
|
capture_data->status.connected = connect(true, capture_data, &frontend_data);
|
|
bool last_connected = capture_data->status.connected;
|
|
SuccessConnectionOutTextGenerator(out_text_data, capture_data);
|
|
int no_data_consecutive = 0;
|
|
|
|
while(capture_data->status.running) {
|
|
|
|
bool polled = false;
|
|
bool poll_everything = true;
|
|
if(poll_timeout > 0) {
|
|
poll_everything = false;
|
|
poll_timeout--;
|
|
}
|
|
else if(frontend_data.display_data.fast_poll)
|
|
poll_timeout = LOW_POLL_DIVISOR;
|
|
VideoOutputData *chosen_buf = out_buf;
|
|
bool blank_out = false;
|
|
bool is_connected = capture_data->status.connected;
|
|
if(is_connected != last_connected) {
|
|
update_connected_specific_settings(&frontend_data, capture_data->status.device);
|
|
no_data_consecutive = 0;
|
|
num_allowed_blanks = MAX_ALLOWED_BLANKS;
|
|
}
|
|
last_connected = is_connected;
|
|
if(is_connected) {
|
|
if(no_data_consecutive > NO_DATA_CONSECUTIVE_THRESHOLD)
|
|
no_data_consecutive = NO_DATA_CONSECUTIVE_THRESHOLD;
|
|
capture_data->status.video_wait.update_time_multiplier(get_time_multiplier(capture_data, no_data_consecutive >= NO_DATA_CONSECUTIVE_THRESHOLD));
|
|
bool timed_out = !capture_data->status.video_wait.timed_lock();
|
|
bool data_processed = false;
|
|
CaptureDataSingleBuffer* data_buffer = capture_data->data_buffers.GetReaderBuffer(CAPTURE_READER_VIDEO);
|
|
|
|
if(data_buffer != NULL) {
|
|
last_frame_time = data_buffer->time_in_buf;
|
|
if(data_buffer->read >= get_video_in_size(capture_data)) {
|
|
if(capture_data->status.cooldown_curr_in)
|
|
blank_out = true;
|
|
else {
|
|
bool conversion_success = convertVideoToOutput(out_buf, endianness, data_buffer, &capture_data->status);
|
|
if(!conversion_success)
|
|
UpdateOutText(out_text_data, "", "Video conversion failed...", TEXT_KIND_NORMAL);
|
|
}
|
|
num_allowed_blanks = MAX_ALLOWED_BLANKS;
|
|
no_data_consecutive = 0;
|
|
data_processed = true;
|
|
}
|
|
capture_data->data_buffers.ReleaseReaderBuffer(CAPTURE_READER_VIDEO);
|
|
}
|
|
if(!data_processed) {
|
|
if(num_allowed_blanks > 0)
|
|
num_allowed_blanks--;
|
|
else
|
|
blank_out = true;
|
|
no_data_consecutive++;
|
|
}
|
|
}
|
|
else {
|
|
default_sleep();
|
|
blank_out = true;
|
|
}
|
|
|
|
if(blank_out) {
|
|
last_frame_time = 0.0;
|
|
chosen_buf = NULL;
|
|
}
|
|
|
|
if(frontend_data.display_data.fast_poll)
|
|
poll_all_windows(&frontend_data, poll_everything, polled);
|
|
|
|
update_output(&frontend_data, last_frame_time, chosen_buf);
|
|
|
|
if(!frontend_data.display_data.fast_poll)
|
|
poll_all_windows(&frontend_data, poll_everything, polled);
|
|
|
|
int load_index = 0;
|
|
int save_index = 0;
|
|
|
|
if(top_screen->open_capture() || bot_screen->open_capture() || joint_screen->open_capture()) {
|
|
capture_data->status.connected = connect(true, capture_data, &frontend_data);
|
|
SuccessConnectionOutTextGenerator(out_text_data, capture_data);
|
|
}
|
|
|
|
check_close_application(top_screen, capture_data, ret_val);
|
|
check_close_application(bot_screen, capture_data, ret_val);
|
|
check_close_application(joint_screen, capture_data, ret_val);
|
|
|
|
if((load_index = top_screen->load_data()) || (load_index = bot_screen->load_data()) || (load_index = joint_screen->load_data())) {
|
|
// This value should only be loaded when starting the program...
|
|
bool previous_last_connected_ds = frontend_data.display_data.last_connected_ds;
|
|
load_layout_file(load_index, &frontend_data, audio_data, out_text_data, &extra_button_shortcuts, &capture_data->status, skip_io, true, created_proper_folder);
|
|
frontend_data.display_data.last_connected_ds = previous_last_connected_ds;
|
|
}
|
|
|
|
if((save_index = top_screen->save_data()) || (save_index = bot_screen->save_data()) || (save_index = joint_screen->save_data())) {
|
|
save_layout_file(save_index, &frontend_data, audio_data, out_text_data, &extra_button_shortcuts, &capture_data->status, skip_io, true, created_proper_folder);
|
|
top_screen->update_save_menu();
|
|
bot_screen->update_save_menu();
|
|
joint_screen->update_save_menu();
|
|
}
|
|
|
|
if(audio_data->has_text_to_print()) {
|
|
UpdateOutText(out_text_data, "", audio_data->text_to_print(), TEXT_KIND_NORMAL);
|
|
}
|
|
|
|
if(capture_data->status.new_error_text) {
|
|
UpdateOutText(out_text_data, capture_data->status.detailed_error_text, capture_data->status.graphical_error_text, TEXT_KIND_ERROR);
|
|
capture_data->status.new_error_text = false;
|
|
}
|
|
|
|
if((!out_text_data.consumed) && (!frontend_data.reload)) {
|
|
ConsoleOutText(out_text_data.full_text);
|
|
top_screen->print_notification(out_text_data.small_text, out_text_data.kind);
|
|
bot_screen->print_notification(out_text_data.small_text, out_text_data.kind);
|
|
joint_screen->print_notification(out_text_data.small_text, out_text_data.kind);
|
|
out_text_data.consumed = true;
|
|
}
|
|
}
|
|
|
|
top_screen->end();
|
|
bot_screen->end();
|
|
joint_screen->end();
|
|
|
|
top_thread.join();
|
|
bot_thread.join();
|
|
joint_thread.join();
|
|
|
|
top_screen->after_thread_join();
|
|
bot_screen->after_thread_join();
|
|
joint_screen->after_thread_join();
|
|
|
|
save_layout_file(STARTUP_FILE_INDEX, &frontend_data, audio_data, out_text_data, &extra_button_shortcuts, &capture_data->status, skip_io, false, created_proper_folder);
|
|
|
|
if(!out_text_data.consumed) {
|
|
ConsoleOutText(out_text_data.full_text);
|
|
out_text_data.consumed = true;
|
|
}
|
|
|
|
delete out_buf;
|
|
return ret_val;
|
|
}
|
|
|
|
static bool create_folder(const std::string path) {
|
|
try {
|
|
#if (!defined(_MSC_VER)) || (_MSC_VER > 1916)
|
|
std::filesystem::create_directories(path);
|
|
#else
|
|
std::experimental::filesystem::create_directories(path);
|
|
#endif
|
|
return true;
|
|
}
|
|
catch(...) {
|
|
std::cerr << "Error creating folder " << path << std::endl;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool create_out_folder() {
|
|
bool success = create_folder(LayoutPathGenerator(STARTUP_FILE_INDEX, true));
|
|
if(!success)
|
|
create_folder(LayoutPathGenerator(STARTUP_FILE_INDEX, false));
|
|
create_folder(LayoutPathGenerator(1, success));
|
|
return success;
|
|
}
|
|
|
|
static bool parse_existence_arg(int &index, char **argv, bool &target, bool existence_value, std::string to_check) {
|
|
if(argv[index] != to_check)
|
|
return false;
|
|
target = existence_value;
|
|
return true;
|
|
}
|
|
|
|
static bool parse_int_arg(int &index, int argc, char **argv, int &target, std::string to_check) {
|
|
if(argv[index] != to_check)
|
|
return false;
|
|
if((++index) >= argc)
|
|
return true;
|
|
try {
|
|
target = std::stoi(argv[index]);
|
|
}
|
|
catch(...) {
|
|
std::cerr << "Error with input for: " << to_check << std::endl;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
init_threads();
|
|
bool mono_app = false;
|
|
int page_up_id = -1;
|
|
int page_down_id = -1;
|
|
int enter_id = -1;
|
|
int power_id = -1;
|
|
bool use_pud_up = true;
|
|
bool created_proper_folder = create_out_folder();
|
|
for (int i = 1; i < argc; i++) {
|
|
if(parse_existence_arg(i, argv, mono_app, true, "--mono_app"))
|
|
continue;
|
|
#ifdef RASPI
|
|
if(parse_int_arg(i, argc, argv, page_up_id, "--pi_select"))
|
|
continue;
|
|
if(parse_int_arg(i, argc, argv, page_down_id, "--pi_menu"))
|
|
continue;
|
|
if(parse_int_arg(i, argc, argv, enter_id, "--pi_enter"))
|
|
continue;
|
|
if(parse_int_arg(i, argc, argv, power_id, "--pi_power"))
|
|
continue;
|
|
if(parse_existence_arg(i, argv, use_pud_up, false, "--pi_pud_down"))
|
|
continue;
|
|
#endif
|
|
std::cout << "Help:" << std::endl;
|
|
std::cout << " --mono_app Enables special mode for when only this application" << std::endl;
|
|
std::cout << " should run on the system. Disabled by default." << std::endl;
|
|
#ifdef RASPI
|
|
std::cout << " --pi_select ID Specifies ID for the select GPIO button." << std::endl;
|
|
std::cout << " --pi_menu ID Specifies ID for the menu GPIO button." << std::endl;
|
|
std::cout << " --pi_enter ID Specifies ID for the enter GPIO button." << std::endl;
|
|
std::cout << " --pi_power ID Specifies ID for the poweroff GPIO button." << std::endl;
|
|
std::cout << " --pi_pud_down Sets the pull-up GPIO mode to down. Default is up." << std::endl;
|
|
#endif
|
|
return 0;
|
|
}
|
|
init_extra_buttons_poll(page_up_id, page_down_id, enter_id, power_id, use_pud_up);
|
|
AudioData audio_data;
|
|
audio_data.reset();
|
|
CaptureData* capture_data = new CaptureData;
|
|
capture_init();
|
|
|
|
std::thread capture_thread(captureCall, capture_data);
|
|
std::thread audio_thread(soundCall, &audio_data, capture_data);
|
|
|
|
int ret_val = mainVideoOutputCall(&audio_data, capture_data, mono_app, created_proper_folder);
|
|
audio_thread.join();
|
|
capture_thread.join();
|
|
delete capture_data;
|
|
end_extra_buttons_poll();
|
|
capture_close();
|
|
|
|
return ret_val;
|
|
}
|