vasingletonmethods.hpp 11 KB
Newer Older
1 2 3
#include <Python.h>
#include <VANetClient.h>
#include <VACore.h>
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
4
#include <VAStruct.h>
5 6 7
#include <VAException.h>
#include <string.h>

8
// If you want to extend the va Python pSelf interface, also add
9 10 11 12
// the function to the va_methods table in vasingleton.cpp - otherwise they will not show up.
// Documentation goes into vasingletondoc.hpp

static IVANetClient* g_pVANetClient = nullptr; //!< Static pointer to VANetClient instance
13
static PyObject* g_pVAError = nullptr; //!< Static pointer to error instance
14

15 16 17 18
// Ugly definitions to ease try-catching VA exceptions
#define VAPY_REQUIRE_CONN_TRY try { RequireCoreAvailable();
#define VAPY_CATCH_RETURN } catch (const CVAException& oError) { PyErr_SetString(PyExc_Exception, oError.ToString().c_str()); return NULL; }

19
//! Helper for API dev
20
static PyObject* va_not_implemented(PyObject*, PyObject*)
21 22
{
	VA_EXCEPT_NOT_IMPLEMENTED;
23
};
24

25 26 27
//! Raises an exception if core is not available
static void RequireCoreAvailable()
{
28 29
	if (!g_pVANetClient)
		VA_EXCEPT2(CVAException::NETWORK_ERROR, "VA client not available, please connect first");
30

31 32 33
	if (!g_pVANetClient->GetCoreInstance())
		VA_EXCEPT2(CVAException::NETWORK_ERROR, "VA client available, but access to VA interface failed. Please reconnect.");
};
34

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
35
//! Helper to convert recursively from VAStruct to Python dict
36
PyObject* ConvertVAStructToPythonDict(const CVAStruct& oInStruct)
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
37
{
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
	PyObject* pOutDict = PyDict_New();

	CVAStruct::const_iterator cit = oInStruct.Begin();
	while (cit != oInStruct.End())
	{
		const std::string sKey((*cit++).first);
		const CVAStructValue& oValue(oInStruct[sKey]);

		PyObject* pNewValue = nullptr;
		if (oValue.IsBool())
		{
			pNewValue = PyBool_FromLong(bool(oValue));
		}
		else if (oValue.IsInt())
		{
			pNewValue = PyLong_FromLong(int(oValue));
		}
		else if (oValue.IsDouble())
		{
			pNewValue = PyFloat_FromDouble(double(oValue));
		}
		else if (oValue.IsString())
		{
			pNewValue = PyUnicode_FromString(std::string(oValue).c_str());
		}
		else if (oValue.IsStruct())
		{
			pNewValue = ConvertVAStructToPythonDict(oValue);
		}
		else if (oValue.IsData())
		{
			VA_EXCEPT_NOT_IMPLEMENTED;
		}
		else if (oValue.IsSampleBuffer())
		{
			VA_EXCEPT_NOT_IMPLEMENTED;
		}
		else
		{
			VA_EXCEPT2(INVALID_PARAMETER, "Could not interpret value of key '" + sKey + "' as a supported python dict type. Value was" + oValue.ToString());
		}

		if (!pNewValue)
			VA_EXCEPT2(INVALID_PARAMETER, "Could not create python object from value of key '" + sKey + "'. Value was" + oValue.ToString());

		if (PyDict_SetItemString(pOutDict, sKey.c_str(), pNewValue) == -1)
			VA_EXCEPT2(INVALID_PARAMETER, "Could not create python object from value of key '" + sKey + "'. Value was" + oValue.ToString());
	}

	return pOutDict;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
88 89 90
};

//! Helper to convert recursively from Python dict to VAStruct
91
CVAStruct ConvertPythonDictToVAStruct(PyObject* pInDict)
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
92
{
93 94 95 96 97 98 99 100 101 102 103
	CVAStruct oReturn;

	PyObject* pKeyList = PyDict_Keys(pInDict);
	PyObject* pValueList = PyDict_Values(pInDict);

	for (Py_ssize_t i = 0; i < PyList_Size(pKeyList); i++)
	{
		PyObject* pKey = PyList_GetItem(pKeyList, i);
		PyObject* pValue = PyList_GetItem(pValueList, i);
		char* pcKeyName = nullptr;
		if (!PyArg_Parse(pKey, "s", &pcKeyName))
104
			VA_EXCEPT2(CVAException::INVALID_PARAMETER, "Invalid key '" + std::string(pcKeyName) + "'");
105 106 107 108 109 110 111

		if (Py_None == pValue)
		{
			oReturn[pcKeyName] = false;
		}
		else if (PyBool_Check(pValue))
		{
112
			oReturn[pcKeyName] = ( PyLong_AsLong(pValue) != 0 );
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
		}
		else if (PyLong_Check(pValue))
		{
			oReturn[pcKeyName] = PyLong_AsLong(pValue);
		}
		else if (PyFloat_Check(pValue))
		{
			oReturn[pcKeyName] = PyFloat_AsDouble(pValue);
		}
		else if (PyUnicode_Check(pValue))
		{
			char* pcStringValue = nullptr;
			if (!PyArg_Parse(pValue, "s", &pcStringValue))
				VA_EXCEPT2(CVAException::INVALID_PARAMETER, "Invalid string value at key '" + std::string(pcKeyName) + "': " + std::string(pcStringValue));
			oReturn[pcKeyName] = std::string(pcStringValue);
		}
		else if (PyDict_Check(pValue))
		{
131
			oReturn[pcKeyName] = ConvertPythonDictToVAStruct(pValue);
132 133 134 135 136 137 138 139 140 141 142 143 144
		}
		else if (PyList_Check(pValue))
		{
			// Sample buffer
			VA_EXCEPT_NOT_IMPLEMENTED;
		}
		else if (PyByteArray_Check(pValue))
		{
			// Data blob
			VA_EXCEPT_NOT_IMPLEMENTED;
		}
		else
		{
145
			VA_EXCEPT2(INVALID_PARAMETER, "Could not interpret value of key '" + std::string(pcKeyName) + "' as a supported VAStruct type.")
146 147 148 149
		}
	}

	return oReturn;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
150 151 152 153 154
};


// ------------------------------- Python module extension methods

155
static PyObject* va_connect(PyObject*, PyObject** ppArgs, Py_ssize_t nArgs, PyObject* pKeywordNames)
156
{
157
	if (!g_pVANetClient)
158 159
		g_pVANetClient = IVANetClient::Create();

160
	if (g_pVANetClient->IsConnected())
161
	{
162
		PyErr_WarnEx(NULL, "Was still connected, forced disconnect.", 1);
163
		g_pVANetClient->Disconnect();
164 165 166
	}

	static const char * const _keywords[] = { "server", "port", NULL };
167
	static _PyArg_Parser _parser = { "|si:connect", _keywords, 0 };
168
	char* pcServerIP = nullptr;
169 170
	int iServerPort = 12340;

171
	if (!_PyArg_ParseStack(ppArgs, nArgs, pKeywordNames, &_parser, &pcServerIP, &iServerPort))
172
		return NULL;
173

174
	std::string sServerIP = pcServerIP ? std::string(pcServerIP) : "localhost";
175

176 177 178 179
	if (IVANetClient::VA_NO_ERROR == g_pVANetClient->Initialize(sServerIP, iServerPort))
		return PyBool_FromLong(1);

	PyErr_SetString(PyExc_ConnectionError, std::string("Could not connect to " + sServerIP + " on " + std::to_string((long)iServerPort)).c_str());
180
	return NULL;
181
};
182

183
static PyObject* va_disconnect(PyObject*, PyObject*)
184
{
185 186
	if (!g_pVANetClient)
		return PyBool_FromLong(0);
187

188
	return PyBool_FromLong(g_pVANetClient->Disconnect());
189
};
190

191
static PyObject* va_is_connected(PyObject*, PyObject*)
192
{
193 194
	if (!g_pVANetClient)
		return PyBool_FromLong(0);
195
	else
196 197
		return PyBool_FromLong(g_pVANetClient->IsConnected());
};
198

199
static PyObject* va_reset(PyObject*, PyObject*)
200
{
201
	VAPY_REQUIRE_CONN_TRY;
202
	g_pVANetClient->GetCoreInstance()->Reset();
203
	Py_INCREF(Py_None);
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
204
	return Py_None;
205 206
	VAPY_CATCH_RETURN;
};
207

208
static PyObject* va_enumerate_modules(PyObject*, PyObject*)
209
{
210
	VAPY_REQUIRE_CONN_TRY;
211 212 213 214

	std::vector< CVAModuleInfo > voModuleInfos;
	g_pVANetClient->GetCoreInstance()->EnumerateModules(voModuleInfos);

Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
215
	PyObject* pModuleList = PyList_New(voModuleInfos.size());
216 217 218 219

	for (size_t i = 0; i < voModuleInfos.size(); i++)
	{
		CVAModuleInfo& oModule(voModuleInfos[i]);
220
		PyObject* pModuleInfo = Py_BuildValue("{s:i,s:s,s:s}", "index", i, "name", oModule.sName.c_str(), "description", oModule.sDesc.c_str());
221 222 223 224 225
		PyList_SetItem(pModuleList, i, pModuleInfo); // steals reference
	}

	return pModuleList;

226 227 228
	VAPY_CATCH_RETURN;
};

229
static PyObject* va_call_module(PyObject*, PyObject** ppArgs, Py_ssize_t nArgs, PyObject* pKeywordNames)
230
{
231
	VAPY_REQUIRE_CONN_TRY;
232

233 234
	static const char * const _keywords[] = { "module_name", "arguments_dict", NULL };
	static _PyArg_Parser _parser = { "sO!:call_module", _keywords, 0 };
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
235
	char* pcModuleName = nullptr;
236
	PyObject* pArgumentsDict = nullptr;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
237

238
	if (!_PyArg_ParseStack(ppArgs, nArgs, pKeywordNames, &_parser, &pcModuleName, &PyDict_Type, &pArgumentsDict))
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
239
		return NULL;
240 241 242

	std::string sModuleName = std::string(pcModuleName);
	CVAStruct oInArgs = ConvertPythonDictToVAStruct(pArgumentsDict);
243
	CVAStruct oOutArgs;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
244

245 246 247
	g_pVANetClient->GetCoreInstance()->CallModule(sModuleName, oInArgs, oOutArgs);

	return ConvertVAStructToPythonDict(oOutArgs);
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
248

249 250 251
	VAPY_CATCH_RETURN;
};

252
static PyObject* va_add_search_path(PyObject*, PyObject** ppArgs, Py_ssize_t nArgs, PyObject* pKeywordNames)
253
{
254
	VAPY_REQUIRE_CONN_TRY;
255

256 257 258 259 260 261 262
	static const char * const _keywords[] = { "directory_path", NULL };
	static _PyArg_Parser _parser = { "s:add_search_path", _keywords, 0 };
	char* pcPath = nullptr;
	if (!_PyArg_ParseStack(ppArgs, nArgs, pKeywordNames, &_parser, &pcPath))
		return NULL;

	return PyBool_FromLong(g_pVANetClient->GetCoreInstance()->AddSearchPath(std::string(pcPath)));
263

264 265 266
	VAPY_CATCH_RETURN;
};

267
static PyObject* va_create_listener(PyObject*, PyObject*)
268
{
269
	VAPY_REQUIRE_CONN_TRY;
270 271

	std::string sName = "PyListener";
272
	int iID = g_pVANetClient->GetCoreInstance()->CreateListener(sName, IVACore::VA_AURAMODE_ALL);
273

274
	return PyLong_FromLong(iID);
275

276 277
	VAPY_CATCH_RETURN;
};
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
278

279
static PyObject* va_is_scene_locked(PyObject*, PyObject*)
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
280
{
281 282
	VAPY_REQUIRE_CONN_TRY;
	return PyLong_FromLong(g_pVANetClient->GetCoreInstance()->IsSceneLocked());
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
283 284 285
	VAPY_CATCH_RETURN;
};

286
static PyObject* va_lock_scene(PyObject* , PyObject*)
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
287
{
288
	VAPY_REQUIRE_CONN_TRY;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
289
	g_pVANetClient->GetCoreInstance()->LockScene();
290
	Py_INCREF(Py_None);
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
291
	return Py_None;
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
292 293 294
	VAPY_CATCH_RETURN;
};

295
static PyObject* va_unlock_scene(PyObject* , PyObject*)
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
296 297
{
	VAPY_REQUIRE_CONN_TRY;
298
	return PyLong_FromLong(g_pVANetClient->GetCoreInstance()->UnlockScene());
Dipl.-Ing. Jonas Stienen's avatar
Dipl.-Ing. Jonas Stienen committed
299 300
	VAPY_CATCH_RETURN;
};
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381

static PyObject* va_load_directivity(PyObject*, PyObject** ppArgs, Py_ssize_t nArgs, PyObject* pKeywordNames)
{
	VAPY_REQUIRE_CONN_TRY;

	static const char * const _keywords[] = { "path", "name", NULL };
	static _PyArg_Parser _parser = { "s|s:load_directivity", _keywords, 0 };
	char* pcPath = nullptr;
	char* pcName = nullptr;
	if (!_PyArg_ParseStack(ppArgs, nArgs, pKeywordNames, &_parser, &pcPath, &pcName))
		return NULL;

	std::string sName = pcName ? std::string(pcName) : "";
	return PyBool_FromLong(g_pVANetClient->GetCoreInstance()->LoadDirectivity(std::string(pcPath), sName));

	VAPY_CATCH_RETURN;
};

static PyObject* va_free_directivity(PyObject*, PyObject** ppArgs, Py_ssize_t nArgs, PyObject* pKeywordNames)
{
	VAPY_REQUIRE_CONN_TRY;

	static const char * const _keywords[] = { "id", NULL };
	static _PyArg_Parser _parser = { "i:free_directivity", _keywords, 0 };
	long iID = -1;
	if (!_PyArg_ParseStack(ppArgs, nArgs, pKeywordNames, &_parser, &iID))
		return NULL;
	return PyBool_FromLong(g_pVANetClient->GetCoreInstance()->FreeDirectivity(iID));

	VAPY_CATCH_RETURN;
};

static PyObject* va_get_directivity_info(PyObject*, PyObject** ppArgs, Py_ssize_t nArgs, PyObject* pKeywordNames)
{
	VAPY_REQUIRE_CONN_TRY;

	static const char * const _keywords[] = { "id", NULL };
	static _PyArg_Parser _parser = { "i:get_directivity_info", _keywords, 0 };
	long iID = -1;
	if (!_PyArg_ParseStack(ppArgs, nArgs, pKeywordNames, &_parser, &iID))
		return NULL;
	
	CVADirectivityInfo oInfo = g_pVANetClient->GetCoreInstance()->GetDirectivityInfo(iID);

	PyObject* pInfo = Py_BuildValue("{s:i,s:s,s:s,s:i,s:s}", 
		"id", oInfo.iID, 
		"name", oInfo.sName.c_str(),
		"filepath", oInfo.sFilename.c_str(),
		"references", oInfo.iReferences,
		"description", oInfo.sDesc.c_str());

	return pInfo;

	VAPY_CATCH_RETURN;
};

static PyObject* va_get_directivity_infos(PyObject*, PyObject*)
{
	VAPY_REQUIRE_CONN_TRY;

	std::vector< CVADirectivityInfo > voInfos;
	g_pVANetClient->GetCoreInstance()->GetDirectivityInfos(voInfos);

	PyObject* pInfoList = PyList_New(voInfos.size());

	for (size_t i = 0; i < voInfos.size(); i++)
	{
		CVADirectivityInfo& oInfo(voInfos[i]);
		PyObject* pInfo = Py_BuildValue("{s:i,s:s,s:s,s:i,s:s}",
			"id", oInfo.iID,
			"name", oInfo.sName.c_str(),
			"filepath", oInfo.sFilename.c_str(),
			"references", oInfo.iReferences,
			"description", oInfo.sDesc.c_str());
		PyList_SetItem(pInfoList, i, pInfo); // steals reference
	}

	return pInfoList;

	VAPY_CATCH_RETURN;
};