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.

587 lines
18KB

  1. /*
  2. Copyright (C) 2003-2007 Jussi Laako <jussi@sonarnerd.net>
  3. Copyright (C) 2008 Grame & RTL 2008
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #include "driver_interface.h"
  17. #include "JackThreadedDriver.h"
  18. #include "JackOSSDriver.h"
  19. #include "JackEngineControl.h"
  20. #include "JackGraphManager.h"
  21. #include "JackError.h"
  22. #include "JackTime.h"
  23. #include <cstdint>
  24. #include <stdio.h>
  25. using namespace std;
  26. namespace Jack
  27. {
  28. #ifdef JACK_MONITOR
  29. #define CYCLE_POINTS 500000
  30. struct OSSCycle {
  31. jack_time_t fBeforeRead;
  32. jack_time_t fAfterRead;
  33. jack_time_t fAfterReadConvert;
  34. jack_time_t fBeforeWrite;
  35. jack_time_t fAfterWrite;
  36. jack_time_t fBeforeWriteConvert;
  37. };
  38. struct OSSCycleTable {
  39. jack_time_t fBeforeFirstWrite;
  40. jack_time_t fAfterFirstWrite;
  41. OSSCycle fTable[CYCLE_POINTS];
  42. };
  43. OSSCycleTable gCycleTable;
  44. int gCycleCount = 0;
  45. #endif
  46. int JackOSSDriver::Open(jack_nframes_t nframes,
  47. int user_nperiods,
  48. jack_nframes_t samplerate,
  49. bool capturing,
  50. bool playing,
  51. int inchannels,
  52. int outchannels,
  53. bool excl,
  54. bool monitor,
  55. const char* capture_driver_uid,
  56. const char* playback_driver_uid,
  57. jack_nframes_t capture_latency,
  58. jack_nframes_t playback_latency,
  59. int bits,
  60. bool ignorehwbuf)
  61. {
  62. // Store local settings first.
  63. fCapture = capturing;
  64. fPlayback = playing;
  65. fBits = bits;
  66. fIgnoreHW = ignorehwbuf;
  67. fNperiods = user_nperiods;
  68. fExcl = excl;
  69. // Generic JackAudioDriver Open
  70. if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, inchannels, outchannels, monitor,
  71. capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) {
  72. return -1;
  73. } else {
  74. #ifdef JACK_MONITOR
  75. // Force memory page in
  76. memset(&gCycleTable, 0, sizeof(gCycleTable));
  77. #endif
  78. if (OpenAux() < 0) {
  79. Close();
  80. return -1;
  81. } else {
  82. fChannel.StartAssistThread(fEngineControl->fRealTime, fEngineControl->fServerPriority);
  83. return 0;
  84. }
  85. }
  86. }
  87. int JackOSSDriver::Close()
  88. {
  89. #ifdef JACK_MONITOR
  90. FILE* file = fopen("OSSProfiling.log", "w");
  91. if (file) {
  92. jack_info("Writing OSS driver timing data....");
  93. for (int i = 1; i < gCycleCount; i++) {
  94. int d1 = gCycleTable.fTable[i].fAfterRead - gCycleTable.fTable[i].fBeforeRead;
  95. int d2 = gCycleTable.fTable[i].fAfterReadConvert - gCycleTable.fTable[i].fAfterRead;
  96. int d3 = gCycleTable.fTable[i].fAfterWrite - gCycleTable.fTable[i].fBeforeWrite;
  97. int d4 = gCycleTable.fTable[i].fBeforeWrite - gCycleTable.fTable[i].fBeforeWriteConvert;
  98. fprintf(file, "%d \t %d \t %d \t %d \t \n", d1, d2, d3, d4);
  99. }
  100. fclose(file);
  101. } else {
  102. jack_error("JackOSSDriver::Close : cannot open OSSProfiling.log file");
  103. }
  104. file = fopen("TimingOSS.plot", "w");
  105. if (file == NULL) {
  106. jack_error("JackOSSDriver::Close cannot open TimingOSS.plot file");
  107. } else {
  108. fprintf(file, "set grid\n");
  109. fprintf(file, "set title \"OSS audio driver timing\"\n");
  110. fprintf(file, "set xlabel \"audio cycles\"\n");
  111. fprintf(file, "set ylabel \"usec\"\n");
  112. fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
  113. \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
  114. \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
  115. \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
  116. fprintf(file, "set output 'TimingOSS.pdf\n");
  117. fprintf(file, "set terminal pdf\n");
  118. fprintf(file, "set grid\n");
  119. fprintf(file, "set title \"OSS audio driver timing\"\n");
  120. fprintf(file, "set xlabel \"audio cycles\"\n");
  121. fprintf(file, "set ylabel \"usec\"\n");
  122. fprintf(file, "plot \"OSSProfiling.log\" using 1 title \"Driver read wait\" with lines, \
  123. \"OSSProfiling.log\" using 2 title \"Driver read convert duration\" with lines, \
  124. \"OSSProfiling.log\" using 3 title \"Driver write wait\" with lines, \
  125. \"OSSProfiling.log\" using 4 title \"Driver write convert duration\" with lines\n");
  126. fclose(file);
  127. }
  128. #endif
  129. fChannel.Lock();
  130. fChannel.StopAssistThread();
  131. fChannel.Unlock();
  132. int res = JackAudioDriver::Close();
  133. CloseAux();
  134. return res;
  135. }
  136. int JackOSSDriver::OpenAux()
  137. {
  138. if (!fChannel.Lock()) {
  139. return -1;
  140. }
  141. // (Re-)Initialize runtime variables.
  142. fCycleEnd = 0;
  143. fLastRun = 0;
  144. fMaxRunGap = 0;
  145. if (!fChannel.InitialSetup(fEngineControl->fSampleRate)) {
  146. fChannel.Unlock();
  147. return -1;
  148. }
  149. if (fCapture) {
  150. if (!fChannel.OpenCapture(fCaptureDriverName, fExcl, fBits, fCaptureChannels)) {
  151. fChannel.Unlock();
  152. return -1;
  153. }
  154. }
  155. if (fPlayback) {
  156. if (!fChannel.OpenPlayback(fPlaybackDriverName, fExcl, fBits, fPlaybackChannels)) {
  157. fChannel.Unlock();
  158. return -1;
  159. }
  160. }
  161. if (!fChannel.StartChannels(fEngineControl->fBufferSize)) {
  162. fChannel.Unlock();
  163. return -1;
  164. }
  165. if (fCapture) {
  166. fChannel.Capture().log_device_info();
  167. }
  168. if (fPlayback) {
  169. fChannel.Playback().log_device_info();
  170. }
  171. if (size_t max_channels = std::max(fCaptureChannels, fPlaybackChannels)) {
  172. fSampleBuffers = new jack_sample_t * [max_channels];
  173. }
  174. if (!fChannel.Unlock()) {
  175. return -1;
  176. }
  177. return 0;
  178. }
  179. void JackOSSDriver::CloseAux()
  180. {
  181. fChannel.Lock();
  182. fChannel.StopChannels();
  183. if (fSampleBuffers) {
  184. delete[] fSampleBuffers;
  185. fSampleBuffers = nullptr;
  186. }
  187. fChannel.Unlock();
  188. }
  189. int JackOSSDriver::Read()
  190. {
  191. #ifdef JACK_MONITOR
  192. gCycleTable.fTable[gCycleCount].fBeforeRead = GetMicroSeconds();
  193. #endif
  194. if (!fChannel.Lock()) {
  195. return -1;
  196. }
  197. // Mark the end time of this cycle, in frames.
  198. fCycleEnd += fEngineControl->fBufferSize;
  199. // Process read and write channels at least once.
  200. std::int64_t channel_stamp = fChannel.FrameStamp();
  201. if (!fChannel.CheckTimeAndRun()) {
  202. fChannel.Unlock();
  203. return -1;
  204. }
  205. if (fChannel.FrameStamp() - fLastRun > fMaxRunGap) {
  206. fMaxRunGap = fChannel.FrameStamp() - fLastRun;
  207. std::int64_t channel_gap = fChannel.FrameStamp() - channel_stamp;
  208. jack_log("JackOSSDriver::Read max run gap %lld frames vs channel %lld.", fMaxRunGap, channel_gap);
  209. }
  210. // Check for over- and underruns.
  211. if (fChannel.XRunGap() > 0) {
  212. std::int64_t skip = fChannel.XRunGap() + fEngineControl->fBufferSize;
  213. NotifyXRun(GetMicroSeconds(), (float) (fChannel.FrameClock().frames_to_time(skip) / 1000));
  214. fCycleEnd += skip;
  215. jack_error("JackOSSDriver::Read(): XRun, late by %lld frames.", skip);
  216. fChannel.ResetBuffers(skip);
  217. }
  218. // Wait and process channels until read, or else write, buffer is finished.
  219. while ((fCapture && !fChannel.CaptureFinished()) ||
  220. (!fCapture && !fChannel.PlaybackFinished())) {
  221. if (!(fChannel.Sleep() && fChannel.CheckTimeAndRun())) {
  222. fChannel.Unlock();
  223. return -1;
  224. }
  225. }
  226. // Keep begin cycle time
  227. JackDriver::CycleTakeBeginTime();
  228. if (!fCapture) {
  229. if (!fChannel.Unlock()) {
  230. return -1;
  231. }
  232. return 0;
  233. }
  234. if ((fChannel.FrameStamp() / fEngineControl->fBufferSize) % ((5 * fEngineControl->fSampleRate) / fEngineControl->fBufferSize) == 0) {
  235. fChannel.Capture().log_state(fChannel.FrameStamp());
  236. fMaxRunGap = 0;
  237. }
  238. #ifdef JACK_MONITOR
  239. gCycleTable.fTable[gCycleCount].fAfterRead = GetMicroSeconds();
  240. #endif
  241. for (int i = 0; i < fCaptureChannels; i++) {
  242. fSampleBuffers[i] = nullptr;
  243. if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) {
  244. fSampleBuffers[i] = GetInputBuffer(i);
  245. }
  246. }
  247. std::int64_t buffer_end = fCycleEnd + fEngineControl->fBufferSize;
  248. if (!fChannel.Read(fSampleBuffers, fEngineControl->fBufferSize, buffer_end)) {
  249. fChannel.Unlock();
  250. return -1;
  251. }
  252. #ifdef JACK_MONITOR
  253. gCycleTable.fTable[gCycleCount].fAfterReadConvert = GetMicroSeconds();
  254. #endif
  255. if (!fChannel.CheckTimeAndRun() || !fChannel.Unlock()) {
  256. return -1;
  257. }
  258. fLastRun = fChannel.FrameStamp();
  259. return 0;
  260. }
  261. int JackOSSDriver::Write()
  262. {
  263. if (!fPlayback) {
  264. return 0;
  265. }
  266. if (!fChannel.Lock()) {
  267. return -1;
  268. }
  269. // Process read and write channels at least once.
  270. std::int64_t channel_stamp = fChannel.FrameStamp();
  271. if (!fChannel.CheckTimeAndRun()) {
  272. fChannel.Unlock();
  273. return -1;
  274. }
  275. if (fChannel.FrameStamp() - fLastRun > fMaxRunGap) {
  276. fMaxRunGap = fChannel.FrameStamp() - fLastRun;
  277. std::int64_t channel_gap = fChannel.FrameStamp() - channel_stamp;
  278. jack_log("JackOSSDriver::Write max run gap %lld frames vs channel %lld.", fMaxRunGap, channel_gap);
  279. }
  280. // Wait and process channels until write buffer is finished.
  281. while (!fChannel.PlaybackFinished()) {
  282. if (!(fChannel.Sleep() && fChannel.CheckTimeAndRun())) {
  283. fChannel.Unlock();
  284. return -1;
  285. }
  286. }
  287. if ((fChannel.FrameStamp() / fEngineControl->fBufferSize) % ((5 * fEngineControl->fSampleRate) / fEngineControl->fBufferSize) == 0) {
  288. fChannel.Playback().log_state(fChannel.FrameStamp());
  289. fMaxRunGap = 0;
  290. }
  291. #ifdef JACK_MONITOR
  292. gCycleTable.fTable[gCycleCount].fBeforeWriteConvert = GetMicroSeconds();
  293. #endif
  294. for (int i = 0; i < fPlaybackChannels; i++) {
  295. fSampleBuffers[i] = nullptr;
  296. if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) {
  297. fSampleBuffers[i] = GetOutputBuffer(i);
  298. }
  299. }
  300. std::int64_t buffer_end = fCycleEnd + fEngineControl->fBufferSize;
  301. if (!fChannel.Write(fSampleBuffers, fEngineControl->fBufferSize, buffer_end)) {
  302. fChannel.Unlock();
  303. return -1;
  304. }
  305. #ifdef JACK_MONITOR
  306. gCycleTable.fTable[gCycleCount].fBeforeWrite = GetMicroSeconds();
  307. #endif
  308. // Do a processing step here.
  309. if (!fChannel.CheckTimeAndRun()) {
  310. fChannel.Unlock();
  311. return -1;
  312. }
  313. fLastRun = fChannel.FrameStamp();
  314. #ifdef JACK_MONITOR
  315. gCycleTable.fTable[gCycleCount].fAfterWrite = GetMicroSeconds();
  316. gCycleCount = (gCycleCount == CYCLE_POINTS - 1) ? gCycleCount: gCycleCount + 1;
  317. #endif
  318. if (!fChannel.Unlock()) {
  319. return -1;
  320. }
  321. return 0;
  322. }
  323. void JackOSSDriver::UpdateLatencies()
  324. {
  325. // Reimplement from JackAudioDriver. Base latency is smaller, and there's
  326. // additional latency due to OSS playback buffer management.
  327. jack_latency_range_t input_range;
  328. jack_latency_range_t output_range;
  329. for (int i = 0; i < fCaptureChannels; i++) {
  330. input_range.max = input_range.min = (fEngineControl->fBufferSize / 2) + fCaptureLatency;
  331. fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &input_range);
  332. }
  333. for (int i = 0; i < fPlaybackChannels; i++) {
  334. // TODO: Move this half period to capture latency.
  335. output_range.max = (fEngineControl->fBufferSize / 2) + fPlaybackLatency;
  336. // Additional latency introduced by the OSS buffer.
  337. output_range.max += fNperiods * fEngineControl->fBufferSize;
  338. // Plus one period if in async mode.
  339. if (!fEngineControl->fSyncMode) {
  340. output_range.max += fEngineControl->fBufferSize;
  341. }
  342. output_range.min = output_range.max;
  343. fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &output_range);
  344. }
  345. }
  346. int JackOSSDriver::SetBufferSize(jack_nframes_t buffer_size)
  347. {
  348. // Close and reopen device, we have to adjust the OSS buffer management.
  349. CloseAux();
  350. JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails
  351. return OpenAux();
  352. }
  353. } // end of namespace
  354. #ifdef __cplusplus
  355. extern "C"
  356. {
  357. #endif
  358. SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
  359. {
  360. jack_driver_desc_t * desc;
  361. jack_driver_desc_filler_t filler;
  362. jack_driver_param_value_t value;
  363. desc = jack_driver_descriptor_construct("oss", JackDriverMaster, "OSS API based audio backend", &filler);
  364. value.ui = OSS_DRIVER_DEF_FS;
  365. jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
  366. value.ui = OSS_DRIVER_DEF_BLKSIZE;
  367. jack_driver_descriptor_add_parameter(desc, &filler, "period", 'p', JackDriverParamUInt, &value, NULL, "Frames per period", NULL);
  368. value.ui = OSS_DRIVER_DEF_NPERIODS;
  369. jack_driver_descriptor_add_parameter(desc, &filler, "nperiods", 'n', JackDriverParamUInt, &value, NULL, "Number of periods to prefill output buffer", NULL);
  370. value.i = OSS_DRIVER_DEF_BITS;
  371. jack_driver_descriptor_add_parameter(desc, &filler, "wordlength", 'w', JackDriverParamInt, &value, NULL, "Word length", NULL);
  372. value.ui = OSS_DRIVER_DEF_INS;
  373. jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Capture channels", NULL);
  374. value.ui = OSS_DRIVER_DEF_OUTS;
  375. jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Playback channels", NULL);
  376. value.i = false;
  377. jack_driver_descriptor_add_parameter(desc, &filler, "excl", 'e', JackDriverParamBool, &value, NULL, "Exclusive and direct device access", NULL);
  378. strcpy(value.str, OSS_DRIVER_DEF_DEV);
  379. jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Input device", NULL);
  380. jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Output device", NULL);
  381. jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "OSS device name", NULL);
  382. value.i = false;
  383. jack_driver_descriptor_add_parameter(desc, &filler, "ignorehwbuf", 'b', JackDriverParamBool, &value, NULL, "Ignore hardware period size", NULL);
  384. value.ui = 0;
  385. jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency", NULL);
  386. jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency", NULL);
  387. return desc;
  388. }
  389. SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
  390. {
  391. int bits = OSS_DRIVER_DEF_BITS;
  392. jack_nframes_t srate = OSS_DRIVER_DEF_FS;
  393. jack_nframes_t frames_per_interrupt = OSS_DRIVER_DEF_BLKSIZE;
  394. const char* capture_pcm_name = OSS_DRIVER_DEF_DEV;
  395. const char* playback_pcm_name = OSS_DRIVER_DEF_DEV;
  396. bool capture = false;
  397. bool playback = false;
  398. int chan_in = 0;
  399. int chan_out = 0;
  400. bool monitor = false;
  401. bool excl = false;
  402. unsigned int nperiods = OSS_DRIVER_DEF_NPERIODS;
  403. const JSList *node;
  404. const jack_driver_param_t *param;
  405. bool ignorehwbuf = false;
  406. jack_nframes_t systemic_input_latency = 0;
  407. jack_nframes_t systemic_output_latency = 0;
  408. for (node = params; node; node = jack_slist_next(node)) {
  409. param = (const jack_driver_param_t *)node->data;
  410. switch (param->character) {
  411. case 'r':
  412. srate = param->value.ui;
  413. break;
  414. case 'p':
  415. frames_per_interrupt = (unsigned int)param->value.ui;
  416. break;
  417. case 'n':
  418. nperiods = (unsigned int)param->value.ui;
  419. break;
  420. case 'w':
  421. bits = param->value.i;
  422. break;
  423. case 'i':
  424. chan_in = (int)param->value.ui;
  425. break;
  426. case 'o':
  427. chan_out = (int)param->value.ui;
  428. break;
  429. case 'C':
  430. capture = true;
  431. if (strcmp(param->value.str, "none") != 0) {
  432. capture_pcm_name = param->value.str;
  433. }
  434. break;
  435. case 'P':
  436. playback = true;
  437. if (strcmp(param->value.str, "none") != 0) {
  438. playback_pcm_name = param->value.str;
  439. }
  440. break;
  441. case 'd':
  442. playback_pcm_name = param->value.str;
  443. capture_pcm_name = param->value.str;
  444. break;
  445. case 'b':
  446. ignorehwbuf = true;
  447. break;
  448. case 'e':
  449. excl = true;
  450. break;
  451. case 'I':
  452. systemic_input_latency = param->value.ui;
  453. break;
  454. case 'O':
  455. systemic_output_latency = param->value.ui;
  456. break;
  457. }
  458. }
  459. // duplex is the default
  460. if (!capture && !playback) {
  461. capture = true;
  462. playback = true;
  463. }
  464. Jack::JackOSSDriver* oss_driver = new Jack::JackOSSDriver("system", "oss", engine, table);
  465. Jack::JackDriverClientInterface* threaded_driver = new Jack::JackThreadedDriver(oss_driver);
  466. // Special open for OSS driver...
  467. if (oss_driver->Open(frames_per_interrupt, nperiods, srate, capture, playback, chan_in, chan_out,
  468. excl, monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency, bits, ignorehwbuf) == 0) {
  469. return threaded_driver;
  470. } else {
  471. delete threaded_driver; // Delete the decorated driver
  472. return NULL;
  473. }
  474. }
  475. #ifdef __cplusplus
  476. }
  477. #endif