jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

413 lines
11KB

  1. /*
  2. Copyright (C) 2006-2008 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 2.1 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include "JackConstants.h"
  16. #include "JackDriverLoader.h"
  17. #include "JackTools.h"
  18. #include "JackError.h"
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <assert.h>
  22. #ifdef WIN32
  23. #include <process.h>
  24. #endif
  25. #define DEFAULT_TMP_DIR "/tmp"
  26. using namespace std;
  27. namespace Jack {
  28. char* jack_tmpdir = (char*)DEFAULT_TMP_DIR;
  29. void JackTools::ThrowJackNetException()
  30. {
  31. throw JackNetException();
  32. }
  33. void JackTools::RewriteName(const char* name, char* new_name)
  34. {
  35. size_t i;
  36. for (i = 0; i < strlen(name); i++) {
  37. if ((name[i] == '/') || (name[i] == '\\'))
  38. new_name[i] = '_';
  39. else
  40. new_name[i] = name[i];
  41. }
  42. new_name[i] = '\0';
  43. }
  44. const char* JackTools::DefaultServerName()
  45. {
  46. const char* server_name;
  47. if ((server_name = getenv("JACK_DEFAULT_SERVER")) == NULL)
  48. server_name = JACK_DEFAULT_SERVER_NAME;
  49. return server_name;
  50. }
  51. #ifdef WIN32
  52. void JackTools::KillServer()
  53. {
  54. exit(1);
  55. }
  56. int JackTools::MkDir(const char* path)
  57. {
  58. return CreateDirectory(path, NULL) == 0;
  59. }
  60. int JackTools::GetPID()
  61. {
  62. return _getpid();
  63. }
  64. int JackTools::GetUID()
  65. {
  66. return _getpid();
  67. //#error "No getuid function available"
  68. }
  69. char* JackTools::UserDir()
  70. {
  71. return "";
  72. }
  73. char* JackTools::ServerDir(const char* server_name, char* server_dir)
  74. {
  75. return "";
  76. }
  77. void JackTools::CleanupFiles(const char* server_name) {}
  78. int JackTools::GetTmpdir()
  79. {
  80. return 0;
  81. }
  82. void BuildClientPath(char* path_to_so, int path_len, const char* so_name)
  83. {
  84. snprintf(path_to_so, path_len, ADDON_DIR "/%s.dll", so_name);
  85. }
  86. void PrintLoadError(const char* so_name)
  87. {
  88. // Retrieve the system error message for the last-error code
  89. LPVOID lpMsgBuf;
  90. LPVOID lpDisplayBuf;
  91. DWORD dw = GetLastError();
  92. FormatMessage(
  93. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  94. FORMAT_MESSAGE_FROM_SYSTEM |
  95. FORMAT_MESSAGE_IGNORE_INSERTS,
  96. NULL,
  97. dw,
  98. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  99. (LPTSTR) &lpMsgBuf,
  100. 0, NULL );
  101. // Display the error message and exit the process
  102. lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
  103. (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)so_name) + 40) * sizeof(TCHAR));
  104. _snprintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR),
  105. TEXT("error loading %s err = %s"), so_name, lpMsgBuf);
  106. jack_error((LPCTSTR)lpDisplayBuf);
  107. LocalFree(lpMsgBuf);
  108. LocalFree(lpDisplayBuf);
  109. }
  110. #else
  111. void JackTools::KillServer()
  112. {
  113. kill(GetPID(), SIGINT);
  114. }
  115. int JackTools::MkDir(const char* path)
  116. {
  117. return mkdir(path, 0777) != 0;
  118. }
  119. int JackTools::GetPID()
  120. {
  121. return getpid();
  122. }
  123. int JackTools::GetUID()
  124. {
  125. return getuid();
  126. }
  127. char* JackTools::UserDir()
  128. {
  129. static char user_dir[JACK_PATH_MAX + 1] = "";
  130. /* format the path name on the first call */
  131. if (user_dir[0] == '\0') {
  132. if (getenv ("JACK_PROMISCUOUS_SERVER")) {
  133. snprintf(user_dir, sizeof(user_dir), "%s/jack", jack_tmpdir);
  134. } else {
  135. snprintf(user_dir, sizeof(user_dir), "%s/jack-%d", jack_tmpdir, GetUID());
  136. }
  137. }
  138. return user_dir;
  139. }
  140. char* JackTools::ServerDir(const char* server_name, char* server_dir)
  141. {
  142. /* format the path name into the suppled server_dir char array,
  143. * assuming that server_dir is at least as large as JACK_PATH_MAX + 1 */
  144. snprintf(server_dir, JACK_PATH_MAX + 1, "%s/%s", UserDir(), server_name);
  145. return server_dir;
  146. }
  147. void JackTools::CleanupFiles(const char* server_name)
  148. {
  149. DIR* dir;
  150. struct dirent *dirent;
  151. char dir_name[JACK_PATH_MAX + 1] = "";
  152. ServerDir(server_name, dir_name);
  153. /* On termination, we remove all files that jackd creates so
  154. * subsequent attempts to start jackd will not believe that an
  155. * instance is already running. If the server crashes or is
  156. * terminated with SIGKILL, this is not possible. So, cleanup
  157. * is also attempted when jackd starts.
  158. *
  159. * There are several tricky issues. First, the previous JACK
  160. * server may have run for a different user ID, so its files
  161. * may be inaccessible. This is handled by using a separate
  162. * JACK_TMP_DIR subdirectory for each user. Second, there may
  163. * be other servers running with different names. Each gets
  164. * its own subdirectory within the per-user directory. The
  165. * current process has already registered as `server_name', so
  166. * we know there is no other server actively using that name.
  167. */
  168. /* nothing to do if the server directory does not exist */
  169. if ((dir = opendir(dir_name)) == NULL) {
  170. return;
  171. }
  172. /* unlink all the files in this directory, they are mine */
  173. while ((dirent = readdir(dir)) != NULL) {
  174. char fullpath[JACK_PATH_MAX + 1];
  175. if ((strcmp(dirent->d_name, ".") == 0) || (strcmp (dirent->d_name, "..") == 0)) {
  176. continue;
  177. }
  178. snprintf(fullpath, sizeof(fullpath), "%s/%s", dir_name, dirent->d_name);
  179. if (unlink(fullpath)) {
  180. jack_error("cannot unlink `%s' (%s)", fullpath, strerror(errno));
  181. }
  182. }
  183. closedir(dir);
  184. /* now, delete the per-server subdirectory, itself */
  185. if (rmdir(dir_name)) {
  186. jack_error("cannot remove `%s' (%s)", dir_name, strerror(errno));
  187. }
  188. /* finally, delete the per-user subdirectory, if empty */
  189. if (rmdir(UserDir())) {
  190. if (errno != ENOTEMPTY) {
  191. jack_error("cannot remove `%s' (%s)", UserDir(), strerror(errno));
  192. }
  193. }
  194. }
  195. int JackTools::GetTmpdir()
  196. {
  197. FILE* in;
  198. size_t len;
  199. char buf[JACK_PATH_MAX + 2]; /* allow tmpdir to live anywhere, plus newline, plus null */
  200. if ((in = popen("jackd -l", "r")) == NULL) {
  201. return -1;
  202. }
  203. if (fgets(buf, sizeof(buf), in) == NULL) {
  204. pclose(in);
  205. return -1;
  206. }
  207. len = strlen(buf);
  208. if (buf[len - 1] != '\n') {
  209. /* didn't get a whole line */
  210. pclose(in);
  211. return -1;
  212. }
  213. jack_tmpdir = (char *)malloc(len);
  214. memcpy(jack_tmpdir, buf, len - 1);
  215. jack_tmpdir[len - 1] = '\0';
  216. pclose(in);
  217. return 0;
  218. }
  219. void BuildClientPath(char* path_to_so, int path_len, const char* so_name)
  220. {
  221. const char* internal_dir;
  222. if ((internal_dir = getenv("JACK_INTERNAL_DIR")) == 0) {
  223. if ((internal_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  224. internal_dir = ADDON_DIR;
  225. }
  226. }
  227. snprintf(path_to_so, path_len, "%s/%s.so", internal_dir, so_name);
  228. }
  229. void PrintLoadError(const char* so_name)
  230. {
  231. jack_log("error loading %s err = %s", so_name, dlerror());
  232. }
  233. #endif
  234. template <class T>
  235. JackGnuPlotMonitor<T>::JackGnuPlotMonitor(uint32_t measure_cnt, uint32_t measure_points, std::string name)
  236. {
  237. jack_log ( "JackGnuPlotMonitor::JackGnuPlotMonitor %u measure points - %u measures", measure_points, measure_cnt );
  238. fMeasureCnt = measure_cnt;
  239. fMeasurePoints = measure_points;
  240. fTablePos = 0;
  241. fName = name;
  242. fCurrentMeasure = new T[fMeasurePoints];
  243. fMeasureTable = new T*[fMeasureCnt];
  244. for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ )
  245. {
  246. fMeasureTable[cnt] = new T[fMeasurePoints];
  247. fill_n ( fMeasureTable[cnt], fMeasurePoints, 0 );
  248. }
  249. }
  250. template <class T>
  251. JackGnuPlotMonitor<T>::~JackGnuPlotMonitor()
  252. {
  253. jack_log ( "JackGnuPlotMonitor::~JackGnuPlotMonitor" );
  254. for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ )
  255. delete[] fMeasureTable[cnt];
  256. delete[] fMeasureTable;
  257. delete[] fCurrentMeasure;
  258. }
  259. template <class T>
  260. T JackGnuPlotMonitor<T>::AddNew(T measure_point)
  261. {
  262. fMeasureId = 0;
  263. return fCurrentMeasure[fMeasureId++] = measure_point;
  264. }
  265. template <class T>
  266. uint32_t JackGnuPlotMonitor<T>::New()
  267. {
  268. return fMeasureId = 0;
  269. }
  270. template <class T>
  271. T JackGnuPlotMonitor<T>::Add(T measure_point)
  272. {
  273. return fCurrentMeasure[fMeasureId++] = measure_point;
  274. }
  275. template <class T>
  276. uint32_t JackGnuPlotMonitor<T>::AddLast(T measure_point)
  277. {
  278. fCurrentMeasure[fMeasureId] = measure_point;
  279. fMeasureId = 0;
  280. return Write();
  281. }
  282. template <class T>
  283. uint32_t JackGnuPlotMonitor<T>::Write()
  284. {
  285. for ( uint32_t point = 0; point < fMeasurePoints; point++ )
  286. fMeasureTable[fTablePos][point] = fCurrentMeasure[point];
  287. if ( ++fTablePos == fMeasureCnt )
  288. fTablePos = 0;
  289. return fTablePos;
  290. }
  291. template <class T>
  292. int JackGnuPlotMonitor<T>::Save(std::string name)
  293. {
  294. std::string filename = ( name.empty() ) ? fName : name;
  295. filename += ".log";
  296. jack_log ( "JackGnuPlotMonitor::Save filename %s", filename.c_str() );
  297. std::ofstream file ( filename.c_str() );
  298. for ( uint32_t cnt = 0; cnt < fMeasureCnt; cnt++ )
  299. {
  300. for ( uint32_t point = 0; point < fMeasurePoints; point++ )
  301. file << fMeasureTable[cnt][point] << " \t";
  302. file << std::endl;
  303. }
  304. file.close();
  305. return 0;
  306. }
  307. template <class T>
  308. int JackGnuPlotMonitor<T>::SetPlotFile(std::string* options_list, uint32_t options_number,
  309. std::string* field_names, uint32_t field_number,
  310. std::string name)
  311. {
  312. std::string title = ( name.empty() ) ? fName : name;
  313. std::string plot_filename = title + ".plt";
  314. std::string data_filename = title + ".log";
  315. std::ofstream file ( plot_filename.c_str() );
  316. file << "set multiplot" << std::endl;
  317. file << "set grid" << std::endl;
  318. file << "set title \"" << title << "\"" << std::endl;
  319. for ( uint32_t i = 0; i < options_number; i++ )
  320. file << options_list[i] << std::endl;
  321. file << "plot ";
  322. for ( uint32_t row = 1; row <= field_number; row++ )
  323. {
  324. file << "\"" << data_filename << "\" using " << row << " title \"" << field_names[row-1] << "\" with lines";
  325. file << ( ( row < field_number ) ? ", " : "\n" );
  326. }
  327. jack_log ( "JackGnuPlotMonitor::SetPlotFile - Save GnuPlot file to '%s'", plot_filename.c_str() );
  328. file.close();
  329. return 0;
  330. }
  331. } // end of namespace