/*
* Copyright (C) 2014-2016 Team Kodi
* http://kodi.tv
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this Program; see the file COPYING. If not, see
* .
*
*/
#pragma once
#include "libXBMC_addon.h"
#include "kodi_game_callbacks.h"
#include
#include
#if defined(ANDROID)
#include
#endif
#ifdef _WIN32
#define GAME_HELPER_DLL "\\library.kodi.game\\libKODI_game" ADDON_HELPER_EXT
#else
#define GAME_HELPER_DLL_NAME "libKODI_game-" ADDON_HELPER_ARCH ADDON_HELPER_EXT
#define GAME_HELPER_DLL "/library.kodi.game/" GAME_HELPER_DLL_NAME
#endif
#define GAME_REGISTER_SYMBOL(dll, functionPtr) \
CHelper_libKODI_game::RegisterSymbol(dll, functionPtr, #functionPtr)
class CHelper_libKODI_game
{
public:
CHelper_libKODI_game(void) :
GAME_register_me(nullptr),
GAME_unregister_me(nullptr),
GAME_close_game(nullptr),
GAME_open_pixel_stream(nullptr),
GAME_open_video_stream(nullptr),
GAME_open_pcm_stream(nullptr),
GAME_open_audio_stream(nullptr),
GAME_add_stream_data(nullptr),
GAME_close_stream(nullptr),
GAME_enable_hardware_rendering(nullptr),
GAME_hw_get_current_framebuffer(nullptr),
GAME_hw_get_proc_address(nullptr),
GAME_render_frame(nullptr),
GAME_open_port(nullptr),
GAME_close_port(nullptr),
GAME_input_event(nullptr),
m_handle(nullptr),
m_callbacks(nullptr),
m_libKODI_game(nullptr)
{
}
~CHelper_libKODI_game(void)
{
if (m_libKODI_game)
{
GAME_unregister_me(m_handle, m_callbacks);
dlclose(m_libKODI_game);
}
}
template
static bool RegisterSymbol(void* dll, T& functionPtr, const char* strFunctionPtr)
{
return (functionPtr = (T)dlsym(dll, strFunctionPtr)) != NULL;
}
/*!
* @brief Resolve all callback methods
* @param handle Pointer to the add-on
* @return True when all methods were resolved, false otherwise.
*/
bool RegisterMe(void* handle)
{
m_handle = handle;
std::string libBasePath;
libBasePath = ((cb_array*)m_handle)->libBasePath;
libBasePath += GAME_HELPER_DLL;
#if defined(ANDROID)
struct stat st;
if (stat(libBasePath.c_str(),&st) != 0)
{
std::string tempbin = getenv("XBMC_ANDROID_LIBS");
libBasePath = tempbin + "/" + GAME_HELPER_DLL_NAME;
}
#endif
m_libKODI_game = dlopen(libBasePath.c_str(), RTLD_LAZY);
if (m_libKODI_game == NULL)
{
fprintf(stderr, "Unable to load %s\n", dlerror());
return false;
}
try
{
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_register_me)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_unregister_me)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_close_game)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_open_pixel_stream)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_open_video_stream)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_open_pcm_stream)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_open_audio_stream)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_add_stream_data)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_close_stream)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_enable_hardware_rendering)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_hw_get_current_framebuffer)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_hw_get_proc_address)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_render_frame)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_open_port)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_close_port)) throw false;
if (!GAME_REGISTER_SYMBOL(m_libKODI_game, GAME_input_event)) throw false;
}
catch (const bool& bSuccess)
{
fprintf(stderr, "ERROR: Unable to assign function %s\n", dlerror());
return bSuccess;
}
m_callbacks = GAME_register_me(m_handle);
return m_callbacks != NULL;
}
void CloseGame(void)
{
return GAME_close_game(m_handle, m_callbacks);
}
bool OpenPixelStream(GAME_PIXEL_FORMAT format, unsigned int width, unsigned int height, GAME_VIDEO_ROTATION rotation)
{
return GAME_open_pixel_stream(m_handle, m_callbacks, format, width, height, rotation) == 0;
}
bool OpenVideoStream(GAME_VIDEO_CODEC codec)
{
return GAME_open_video_stream(m_handle, m_callbacks, codec) == 0;
}
bool OpenPCMStream(GAME_PCM_FORMAT format, const GAME_AUDIO_CHANNEL* channel_map)
{
return GAME_open_pcm_stream(m_handle, m_callbacks, format, channel_map) == 0;
}
bool OpenAudioStream(GAME_AUDIO_CODEC codec, const GAME_AUDIO_CHANNEL* channel_map)
{
return GAME_open_audio_stream(m_handle, m_callbacks, codec, channel_map) == 0;
}
void AddStreamData(GAME_STREAM_TYPE stream, const uint8_t* data, unsigned int size)
{
GAME_add_stream_data(m_handle, m_callbacks, stream, data, size);
}
void CloseStream(GAME_STREAM_TYPE stream)
{
GAME_close_stream(m_handle, m_callbacks, stream);
}
void EnableHardwareRendering(const struct game_hw_info* hw_info)
{
return GAME_enable_hardware_rendering(m_handle, m_callbacks, hw_info);
}
uintptr_t HwGetCurrentFramebuffer(void)
{
return GAME_hw_get_current_framebuffer(m_handle, m_callbacks);
}
game_proc_address_t HwGetProcAddress(const char* sym)
{
return GAME_hw_get_proc_address(m_handle, m_callbacks, sym);
}
void RenderFrame()
{
return GAME_render_frame(m_handle, m_callbacks);
}
bool OpenPort(unsigned int port)
{
return GAME_open_port(m_handle, m_callbacks, port);
}
void ClosePort(unsigned int port)
{
return GAME_close_port(m_handle, m_callbacks, port);
}
bool InputEvent(const game_input_event& event)
{
return GAME_input_event(m_handle, m_callbacks, &event);
}
protected:
CB_GameLib* (*GAME_register_me)(void* handle);
void (*GAME_unregister_me)(void* handle, CB_GameLib* cb);
void (*GAME_close_game)(void* handle, CB_GameLib* cb);
int (*GAME_open_pixel_stream)(void* handle, CB_GameLib* cb, GAME_PIXEL_FORMAT, unsigned int, unsigned int, GAME_VIDEO_ROTATION);
int (*GAME_open_video_stream)(void* handle, CB_GameLib* cb, GAME_VIDEO_CODEC);
int (*GAME_open_pcm_stream)(void* handle, CB_GameLib* cb, GAME_PCM_FORMAT, const GAME_AUDIO_CHANNEL*);
int (*GAME_open_audio_stream)(void* handle, CB_GameLib* cb, GAME_AUDIO_CODEC, const GAME_AUDIO_CHANNEL*);
int (*GAME_add_stream_data)(void* handle, CB_GameLib* cb, GAME_STREAM_TYPE, const uint8_t*, unsigned int);
int (*GAME_close_stream)(void* handle, CB_GameLib* cb, GAME_STREAM_TYPE);
void (*GAME_enable_hardware_rendering)(void* handle, CB_GameLib* cb, const struct game_hw_info*);
uintptr_t (*GAME_hw_get_current_framebuffer)(void* handle, CB_GameLib* cb);
game_proc_address_t (*GAME_hw_get_proc_address)(void* handle, CB_GameLib* cb, const char*);
void (*GAME_render_frame)(void* handle, CB_GameLib* cb);
bool (*GAME_open_port)(void* handle, CB_GameLib* cb, unsigned int);
void (*GAME_close_port)(void* handle, CB_GameLib* cb, unsigned int);
bool (*GAME_input_event)(void* handle, CB_GameLib* cb, const game_input_event* event);
private:
void* m_handle;
CB_GameLib* m_callbacks;
void* m_libKODI_game;
struct cb_array
{
const char* libBasePath;
};
};