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.

310 lines
9.6KB

  1. /*
  2. Copyright (C) 2008 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 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 General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #if defined(HAVE_CONFIG_H)
  16. #include "config.h"
  17. #endif
  18. #include "JackAlsaAdapter.h"
  19. #include "JackServer.h"
  20. #include "JackEngineControl.h"
  21. namespace Jack
  22. {
  23. JackAlsaAdapter::JackAlsaAdapter ( jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params ) :
  24. JackAudioAdapterInterface ( buffer_size, sample_rate ),
  25. fThread ( this ),
  26. fAudioInterface ( buffer_size, sample_rate )
  27. {
  28. const JSList* node;
  29. const jack_driver_param_t* param;
  30. fCaptureChannels = 2;
  31. fPlaybackChannels = 2;
  32. fAudioInterface.fPeriod = 2;
  33. for ( node = params; node; node = jack_slist_next ( node ) )
  34. {
  35. param = ( const jack_driver_param_t* ) node->data;
  36. switch ( param->character )
  37. {
  38. case 'i':
  39. fCaptureChannels = param->value.ui;
  40. break;
  41. case 'o':
  42. fPlaybackChannels = param->value.ui;
  43. break;
  44. case 'C':
  45. break;
  46. case 'P':
  47. break;
  48. case 'D':
  49. break;
  50. case 'n':
  51. fAudioInterface.fPeriod = param->value.ui;
  52. break;
  53. case 'd':
  54. fAudioInterface.fCardName = strdup ( param->value.str );
  55. break;
  56. case 'r':
  57. SetAdaptedSampleRate ( param->value.ui );
  58. break;
  59. case 'p':
  60. SetAdaptedBufferSize ( param->value.ui );
  61. break;
  62. }
  63. }
  64. fAudioInterface.setInputs ( fCaptureChannels );
  65. fAudioInterface.setOutputs ( fPlaybackChannels );
  66. }
  67. int JackAlsaAdapter::Open()
  68. {
  69. //open audio interface
  70. if ( fAudioInterface.open() )
  71. return -1;
  72. //start adapter thread
  73. if ( fThread.StartSync() < 0 )
  74. {
  75. jack_error ( "Cannot start audioadapter thread" );
  76. return -1;
  77. }
  78. //display card info
  79. fAudioInterface.longinfo();
  80. //turn the thread realtime
  81. fThread.AcquireRealTime ( JackServer::fInstance->GetEngineControl()->fPriority );
  82. return 0;
  83. }
  84. int JackAlsaAdapter::Close()
  85. {
  86. #ifdef JACK_MONITOR
  87. fTable.Save();
  88. #endif
  89. switch ( fThread.GetStatus() )
  90. {
  91. // Kill the thread in Init phase
  92. case JackThread::kStarting:
  93. case JackThread::kIniting:
  94. if ( fThread.Kill() < 0 )
  95. {
  96. jack_error ( "Cannot kill thread" );
  97. return -1;
  98. }
  99. break;
  100. // Stop when the thread cycle is finished
  101. case JackThread::kRunning:
  102. if ( fThread.Stop() < 0 )
  103. {
  104. jack_error ( "Cannot stop thread" );
  105. return -1;
  106. }
  107. break;
  108. default:
  109. break;
  110. }
  111. return fAudioInterface.close();
  112. }
  113. bool JackAlsaAdapter::Init()
  114. {
  115. //fill the hardware buffers
  116. for ( unsigned int i = 0; i < fAudioInterface.fPeriod; i++ )
  117. fAudioInterface.write();
  118. return true;
  119. }
  120. bool JackAlsaAdapter::Execute()
  121. {
  122. //read data from audio interface
  123. if ( fAudioInterface.read() < 0 )
  124. return false;
  125. bool failure = false;
  126. //compute resampling factor
  127. jack_nframes_t time1, time2;
  128. ResampleFactor ( time1, time2 );
  129. //resample inputs
  130. for ( int i = 0; i < fCaptureChannels; i++ )
  131. {
  132. fCaptureRingBuffer[i]->SetRatio ( time1, time2 );
  133. if ( fCaptureRingBuffer[i]->WriteResample ( fAudioInterface.fInputSoftChannels[i], fAdaptedBufferSize ) < fAdaptedBufferSize )
  134. failure = true;
  135. }
  136. //resample outputs
  137. for ( int i = 0; i < fPlaybackChannels; i++ )
  138. {
  139. fPlaybackRingBuffer[i]->SetRatio ( time2, time1 );
  140. if ( fPlaybackRingBuffer[i]->ReadResample ( fAudioInterface.fOutputSoftChannels[i], fAdaptedBufferSize ) < fAdaptedBufferSize )
  141. failure = true;
  142. }
  143. #ifdef JACK_MONITOR
  144. fTable.Write ( time1, time2, double ( time1 ) / double ( time2 ), double ( time2 ) / double ( time1 ),
  145. fCaptureRingBuffer[0]->ReadSpace(), fPlaybackRingBuffer[0]->WriteSpace() );
  146. #endif
  147. //write data to audio interface
  148. if ( fAudioInterface.write() < 0 )
  149. return false;
  150. //reset all ringbuffers in case of failure
  151. if ( failure )
  152. {
  153. jack_error ( "JackAlsaAdapter::Execute ringbuffer failure... reset" );
  154. ResetRingBuffers();
  155. }
  156. return true;
  157. }
  158. int JackAlsaAdapter::SetSampleRate ( jack_nframes_t sample_rate )
  159. {
  160. JackAudioAdapterInterface::SetHostSampleRate ( sample_rate );
  161. Close();
  162. return Open();
  163. }
  164. int JackAlsaAdapter::SetBufferSize ( jack_nframes_t buffer_size )
  165. {
  166. JackAudioAdapterInterface::SetHostBufferSize ( buffer_size );
  167. Close();
  168. return Open();
  169. }
  170. } // namespace
  171. #ifdef __cplusplus
  172. extern "C"
  173. {
  174. #endif
  175. SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
  176. {
  177. jack_driver_desc_t *desc;
  178. jack_driver_param_desc_t * params;
  179. unsigned int i;
  180. desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
  181. strcpy(desc->name, "audioadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
  182. strcpy(desc->desc, "netjack audio <==> net backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
  183. desc->nparams = 9;
  184. params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
  185. i = 0;
  186. strcpy ( params[i].name, "capture" );
  187. params[i].character = 'C';
  188. params[i].type = JackDriverParamString;
  189. strcpy ( params[i].value.str, "none" );
  190. strcpy ( params[i].short_desc,
  191. "Provide capture ports. Optionally set device" );
  192. strcpy ( params[i].long_desc, params[i].short_desc );
  193. i++;
  194. strcpy ( params[i].name, "playback" );
  195. params[i].character = 'P';
  196. params[i].type = JackDriverParamString;
  197. strcpy ( params[i].value.str, "none" );
  198. strcpy ( params[i].short_desc,
  199. "Provide playback ports. Optionally set device" );
  200. strcpy ( params[i].long_desc, params[i].short_desc );
  201. i++;
  202. strcpy ( params[i].name, "device" );
  203. params[i].character = 'd';
  204. params[i].type = JackDriverParamString;
  205. strcpy ( params[i].value.str, "hw:0" );
  206. strcpy ( params[i].short_desc, "ALSA device name" );
  207. strcpy ( params[i].long_desc, params[i].short_desc );
  208. i++;
  209. strcpy ( params[i].name, "rate" );
  210. params[i].character = 'r';
  211. params[i].type = JackDriverParamUInt;
  212. params[i].value.ui = 48000U;
  213. strcpy ( params[i].short_desc, "Sample rate" );
  214. strcpy ( params[i].long_desc, params[i].short_desc );
  215. i++;
  216. strcpy ( params[i].name, "periodsize" );
  217. params[i].character = 'p';
  218. params[i].type = JackDriverParamUInt;
  219. params[i].value.ui = 512U;
  220. strcpy ( params[i].short_desc, "Period size" );
  221. strcpy ( params[i].long_desc, params[i].short_desc );
  222. i++;
  223. strcpy ( params[i].name, "nperiods" );
  224. params[i].character = 'n';
  225. params[i].type = JackDriverParamUInt;
  226. params[i].value.ui = 2U;
  227. strcpy ( params[i].short_desc, "Number of periods of playback latency" );
  228. strcpy ( params[i].long_desc, params[i].short_desc );
  229. i++;
  230. strcpy ( params[i].name, "duplex" );
  231. params[i].character = 'D';
  232. params[i].type = JackDriverParamBool;
  233. params[i].value.i = 1;
  234. strcpy ( params[i].short_desc,
  235. "Provide both capture and playback ports" );
  236. strcpy ( params[i].long_desc, params[i].short_desc );
  237. i++;
  238. strcpy ( params[i].name, "inchannels" );
  239. params[i].character = 'i';
  240. params[i].type = JackDriverParamUInt;
  241. params[i].value.i = 0;
  242. strcpy ( params[i].short_desc,
  243. "Number of capture channels (defaults to hardware max)" );
  244. strcpy ( params[i].long_desc, params[i].short_desc );
  245. i++;
  246. strcpy ( params[i].name, "outchannels" );
  247. params[i].character = 'o';
  248. params[i].type = JackDriverParamUInt;
  249. params[i].value.i = 0;
  250. strcpy ( params[i].short_desc,
  251. "Number of playback channels (defaults to hardware max)" );
  252. strcpy ( params[i].long_desc, params[i].short_desc );
  253. desc->params = params;
  254. return desc;
  255. }
  256. #ifdef __cplusplus
  257. }
  258. #endif