#include <memory>
#include <map>
#include <stdio.h>
#include <exception>
using namespace std;
namespace ARDOUR {
class AudioBackend;
class AudioEngine;
struct AudioBackendInfo {
const char* name;
/** Using arg1 and arg2, initialize this audiobackend.
*
* Returns zero on success, non-zero otherwise.
*/
int (*instantiate) (const std::string& arg1, const std::string& arg2);
/** Release all resources associated with this audiobackend */
int (*deinstantiate) (void);
/** Factory method to create an AudioBackend-derived class.
*
* Returns a valid shared_ptr to the object if successfull,
* or a "null" shared_ptr otherwise.
*/
std::shared_ptr<AudioBackend> (*factory) (AudioEngine&);
/** Return true if the underlying mechanism/API has been
* configured and does not need (re)configuration in order
* to be usable. Return false otherwise.
*
* Note that this may return true if (re)configuration, even though
* not currently required, is still possible.
*/
bool (*already_configured) ();
/** Return true if the underlying mechanism/API can be
* used on the given system.
*
* If this function returns false, the backend is not
* listed in the engine dialog.
*/
bool (*available) ();
};
/** AudioBackend is an high-level abstraction for interacting with the operating system's
* audio and midi I/O.
*/
class AudioBackend {};
};
namespace ARDOUR {
class AudioEngine;
class AAudio : public AudioBackend {
public:
std::string _instance_name;
static AudioBackendInfo _descriptor;
static std::shared_ptr<AudioBackend> backend_factory (AudioEngine& e);
static int instantiate (const std::string& arg1, const std::string& /* arg2 */);
static int deinstantiate ();
static bool already_configured ();
static bool available ();
static ARDOUR::AudioBackendInfo* descriptor();
};
static std::string s_instance_name;
const size_t _max_buffer_size = 8192;
static std::shared_ptr<AAudio> _instance;
#define N_CHANNELS (2)
ARDOUR::AudioBackendInfo AAudio::_descriptor = {
"AAudio",
instantiate,
deinstantiate,
backend_factory,
already_configured,
available
};
std::shared_ptr<AudioBackend>
AAudio::backend_factory (AudioEngine& e)
{
if (!_instance) {
_instance.reset(new AAudio());
}
return _instance;
}
int
AAudio::instantiate (const std::string& arg1, const std::string& /* arg2 */)
{
s_instance_name = arg1;
return 0;
}
int
AAudio::deinstantiate ()
{
_instance.reset ();
return 0;
}
bool
AAudio::already_configured ()
{
return false;
}
bool
AAudio::available ()
{
return true;
}
ARDOUR::AudioBackendInfo* AAudio::descriptor ()
{
return &_descriptor;
}
}
namespace ARDOUR {
class AudioBackend;
struct AudioBackendInfo;
static std::shared_ptr<AudioBackend> _backend;
class AudioEngine {
public:
AudioEngine ();
static AudioEngine* create ();
int discover_backends();
std::shared_ptr<AudioBackend> set_backend (const std::string&, const std::string& arg1, const std::string& arg2);
std::shared_ptr<AudioBackend> current_backend() const { return _backend; }
static AudioEngine* _instance;
typedef std::map<std::string, AudioBackendInfo *> BackendMap;
BackendMap _backends;
void drop_backend();
};
AudioEngine* AudioEngine::_instance = 0;
AudioEngine::AudioEngine ()
{
discover_backends ();
}
AudioEngine*
AudioEngine::create ()
{
if (_instance) {
return _instance;
}
_instance = new AudioEngine ();
return _instance;
}
int
AudioEngine::discover_backends ()
{
_backends.clear ();
_backends.insert (make_pair (AAudio::descriptor()->name, AAudio::descriptor()));
return _backends.size();
}
void
AudioEngine::drop_backend ()
{
if (_backend) {
_backend.reset ();
}
}
class failed_constructor : public std::exception {
public:
virtual const char *what() const throw() { return "failed constructor"; }
};
std::shared_ptr<AudioBackend>
AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
{
BackendMap::iterator b = _backends.find (name);
if (b == _backends.end()) {
return std::shared_ptr<AudioBackend>();
}
drop_backend ();
try {
if (b->second->instantiate (arg1, arg2)) {
throw failed_constructor ();
}
_backend = b->second->factory (*this);
} catch (exception& e) {
printf("Could not create backend for %s: %s\n", name, e.what());
return std::shared_ptr<AudioBackend>();
}
return _backend;
}
}
using namespace ARDOUR;
int main() {
AudioEngine * engine = nullptr;
engine = AudioEngine::create();
if (!engine->set_backend ("AAudio", "Unit-Test", "")) {
printf("Cannot create Audio/MIDI engine.\n");
abort();
}
if (_backend == nullptr) {
printf("backend dissapeared!\n"); // triggers on android
abort();
}
return 0;
}