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.

580 lines
21KB

  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. #include "JackCoreAudioIOAdapter.h"
  16. #include "JackError.h"
  17. #include <unistd.h>
  18. namespace Jack
  19. {
  20. static void printError(OSStatus err)
  21. {
  22. switch (err) {
  23. case kAudioHardwareNoError:
  24. jack_log("error code : kAudioHardwareNoError");
  25. break;
  26. case kAudioConverterErr_FormatNotSupported:
  27. jack_log("error code : kAudioConverterErr_FormatNotSupported");
  28. break;
  29. case kAudioConverterErr_OperationNotSupported:
  30. jack_log("error code : kAudioConverterErr_OperationNotSupported");
  31. break;
  32. case kAudioConverterErr_PropertyNotSupported:
  33. jack_log("error code : kAudioConverterErr_PropertyNotSupported");
  34. break;
  35. case kAudioConverterErr_InvalidInputSize:
  36. jack_log("error code : kAudioConverterErr_InvalidInputSize");
  37. break;
  38. case kAudioConverterErr_InvalidOutputSize:
  39. jack_log("error code : kAudioConverterErr_InvalidOutputSize");
  40. break;
  41. case kAudioConverterErr_UnspecifiedError:
  42. jack_log("error code : kAudioConverterErr_UnspecifiedError");
  43. break;
  44. case kAudioConverterErr_BadPropertySizeError:
  45. jack_log("error code : kAudioConverterErr_BadPropertySizeError");
  46. break;
  47. case kAudioConverterErr_RequiresPacketDescriptionsError:
  48. jack_log("error code : kAudioConverterErr_RequiresPacketDescriptionsError");
  49. break;
  50. case kAudioConverterErr_InputSampleRateOutOfRange:
  51. jack_log("error code : kAudioConverterErr_InputSampleRateOutOfRange");
  52. break;
  53. case kAudioConverterErr_OutputSampleRateOutOfRange:
  54. jack_log("error code : kAudioConverterErr_OutputSampleRateOutOfRange");
  55. break;
  56. case kAudioHardwareNotRunningError:
  57. jack_log("error code : kAudioHardwareNotRunningError");
  58. break;
  59. case kAudioHardwareUnknownPropertyError:
  60. jack_log("error code : kAudioHardwareUnknownPropertyError");
  61. break;
  62. case kAudioHardwareIllegalOperationError:
  63. jack_log("error code : kAudioHardwareIllegalOperationError");
  64. break;
  65. case kAudioHardwareBadDeviceError:
  66. jack_log("error code : kAudioHardwareBadDeviceError");
  67. break;
  68. case kAudioHardwareBadStreamError:
  69. jack_log("error code : kAudioHardwareBadStreamError");
  70. break;
  71. case kAudioDeviceUnsupportedFormatError:
  72. jack_log("error code : kAudioDeviceUnsupportedFormatError");
  73. break;
  74. case kAudioDevicePermissionsError:
  75. jack_log("error code : kAudioDevicePermissionsError");
  76. break;
  77. case kAudioHardwareBadObjectError:
  78. jack_log("error code : kAudioHardwareBadObjectError");
  79. break;
  80. case kAudioHardwareUnsupportedOperationError:
  81. jack_log("error code : kAudioHardwareUnsupportedOperationError");
  82. break;
  83. default:
  84. jack_log("error code : unknown");
  85. break;
  86. }
  87. }
  88. OSStatus JackCoreAudioIOAdapter::SRNotificationCallback(AudioDeviceID inDevice,
  89. UInt32 inChannel,
  90. Boolean isInput,
  91. AudioDevicePropertyID inPropertyID,
  92. void* inClientData)
  93. {
  94. JackCoreAudioIOAdapter* driver = static_cast<JackCoreAudioIOAdapter*>(inClientData);
  95. switch (inPropertyID) {
  96. case kAudioDevicePropertyNominalSampleRate: {
  97. jack_log("JackCoreAudioDriver::SRNotificationCallback kAudioDevicePropertyNominalSampleRate");
  98. driver->fState = true;
  99. break;
  100. }
  101. }
  102. return noErr;
  103. }
  104. OSStatus JackCoreAudioIOAdapter::Render(void *inRefCon,
  105. AudioUnitRenderActionFlags *ioActionFlags,
  106. const AudioTimeStamp *inTimeStamp,
  107. UInt32 inBusNumber,
  108. UInt32 inNumberFrames,
  109. AudioBufferList *ioData)
  110. {
  111. JackCoreAudioIOAdapter* adapter = static_cast<JackCoreAudioIOAdapter*>(inRefCon);
  112. AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData);
  113. if (!adapter->fRunning) {
  114. adapter->fRunning = true;
  115. jack_time_t time = jack_get_time();
  116. adapter->fProducerDLL.Init(time);
  117. adapter->fConsumerDLL.Init(time);
  118. }
  119. // DLL
  120. jack_time_t time = jack_get_time();
  121. adapter->fProducerDLL.IncFrame(time);
  122. jack_nframes_t time1 = adapter->fConsumerDLL.Time2Frames(time);
  123. jack_nframes_t time2 = adapter->fProducerDLL.Time2Frames(time);
  124. double src_ratio_output = double(time2) / double(time1);
  125. double src_ratio_input = double(time1) / double(time2);
  126. if (src_ratio_input < 0.7f || src_ratio_input > 1.3f) {
  127. jack_error("src_ratio_input = %f", src_ratio_input);
  128. src_ratio_input = 1;
  129. time1 = 1;
  130. time2 = 1;
  131. }
  132. if (src_ratio_output < 0.7f || src_ratio_output > 1.3f) {
  133. jack_error("src_ratio_output = %f", src_ratio_output);
  134. src_ratio_output = 1;
  135. time1 = 1;
  136. time2 = 1;
  137. }
  138. src_ratio_input = Range(0.7f, 1.3f, src_ratio_input);
  139. src_ratio_output = Range(0.7f, 1.3f, src_ratio_output);
  140. jack_log("Callback resampler src_ratio_input = %f src_ratio_output = %f", src_ratio_input, src_ratio_output);
  141. for (int i = 0; i < adapter->fCaptureChannels; i++) {
  142. adapter->fCaptureRingBuffer[i]->SetRatio(time1, time2);
  143. adapter->fCaptureRingBuffer[i]->WriteResample((float*)adapter->fInputData->mBuffers[i].mData, inNumberFrames);
  144. }
  145. for (int i = 0; i < adapter->fPlaybackChannels; i++) {
  146. adapter->fPlaybackRingBuffer[i]->SetRatio(time2, time1);
  147. adapter->fPlaybackRingBuffer[i]->ReadResample((float*)ioData->mBuffers[i].mData, inNumberFrames);
  148. }
  149. return noErr;
  150. }
  151. OSStatus JackCoreAudioIOAdapter::GetDefaultDevice(AudioDeviceID* id)
  152. {
  153. OSStatus res;
  154. UInt32 theSize = sizeof(UInt32);
  155. AudioDeviceID inDefault;
  156. AudioDeviceID outDefault;
  157. if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &theSize, &inDefault)) != noErr)
  158. return res;
  159. if ((res = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &theSize, &outDefault)) != noErr)
  160. return res;
  161. jack_log("GetDefaultDevice: input = %ld output = %ld", inDefault, outDefault);
  162. // Get the device only if default input and ouput are the same
  163. if (inDefault == outDefault) {
  164. *id = inDefault;
  165. return noErr;
  166. } else {
  167. jack_error("Default input and output devices are not the same !!");
  168. return kAudioHardwareBadDeviceError;
  169. }
  170. }
  171. OSStatus JackCoreAudioIOAdapter::GetTotalChannels(AudioDeviceID device, int* channelCount, bool isInput)
  172. {
  173. OSStatus err = noErr;
  174. UInt32 outSize;
  175. Boolean outWritable;
  176. AudioBufferList* bufferList = 0;
  177. *channelCount = 0;
  178. err = AudioDeviceGetPropertyInfo(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, &outWritable);
  179. if (err == noErr) {
  180. bufferList = (AudioBufferList*)malloc(outSize);
  181. err = AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyStreamConfiguration, &outSize, bufferList);
  182. if (err == noErr) {
  183. for (unsigned int i = 0; i < bufferList->mNumberBuffers; i++)
  184. *channelCount += bufferList->mBuffers[i].mNumberChannels;
  185. }
  186. if (bufferList)
  187. free(bufferList);
  188. }
  189. return err;
  190. }
  191. // Setup
  192. int JackCoreAudioIOAdapter::SetupDevices(const char* capture_driver_uid,
  193. const char* playback_driver_uid,
  194. char* capture_driver_name,
  195. char* playback_driver_name)
  196. {
  197. if (GetDefaultDevice(&fDeviceID) != noErr) {
  198. jack_error("Cannot open default device");
  199. return -1;
  200. }
  201. return 0;
  202. }
  203. int JackCoreAudioIOAdapter::SetupChannels(bool capturing,
  204. bool playing,
  205. int& inchannels,
  206. int& outchannels,
  207. int& in_nChannels,
  208. int& out_nChannels,
  209. bool strict)
  210. {
  211. OSStatus err = noErr;
  212. err = GetTotalChannels(fDeviceID, &in_nChannels, true);
  213. if (err != noErr) {
  214. jack_error("Cannot get input channel number");
  215. printError(err);
  216. return -1;
  217. }
  218. err = GetTotalChannels(fDeviceID, &out_nChannels, false);
  219. if (err != noErr) {
  220. jack_error("Cannot get output channel number");
  221. printError(err);
  222. return -1;
  223. }
  224. return 0;
  225. }
  226. int JackCoreAudioIOAdapter::SetupBufferSizeAndSampleRate(jack_nframes_t nframes, jack_nframes_t samplerate)
  227. {
  228. OSStatus err = noErr;
  229. UInt32 outSize;
  230. Float64 sampleRate;
  231. // Setting buffer size
  232. outSize = sizeof(UInt32);
  233. err = AudioDeviceSetProperty(fDeviceID, NULL, 0, false, kAudioDevicePropertyBufferFrameSize, outSize, &nframes);
  234. if (err != noErr) {
  235. jack_error("Cannot set buffer size %ld", nframes);
  236. printError(err);
  237. return -1;
  238. }
  239. // Get sample rate
  240. outSize = sizeof(Float64);
  241. err = AudioDeviceGetProperty(fDeviceID, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, &outSize, &sampleRate);
  242. if (err != noErr) {
  243. jack_error("Cannot get current sample rate");
  244. printError(err);
  245. return -1;
  246. }
  247. // If needed, set new sample rate
  248. if (samplerate != (jack_nframes_t)sampleRate) {
  249. sampleRate = (Float64)samplerate;
  250. // To get SR change notification
  251. err = AudioDeviceAddPropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback, this);
  252. if (err != noErr) {
  253. jack_error("Error calling AudioDeviceAddPropertyListener with kAudioDevicePropertyNominalSampleRate");
  254. printError(err);
  255. return -1;
  256. }
  257. err = AudioDeviceSetProperty(fDeviceID, NULL, 0, kAudioDeviceSectionGlobal, kAudioDevicePropertyNominalSampleRate, outSize, &sampleRate);
  258. if (err != noErr) {
  259. jack_error("Cannot set sample rate = %ld", samplerate);
  260. printError(err);
  261. return -1;
  262. }
  263. // Waiting for SR change notification
  264. int count = 0;
  265. while (!fState && count++ < 100) {
  266. usleep(100000);
  267. jack_log("Wait count = %ld", count);
  268. }
  269. // Remove SR change notification
  270. AudioDeviceRemovePropertyListener(fDeviceID, 0, true, kAudioDevicePropertyNominalSampleRate, SRNotificationCallback);
  271. }
  272. return 0;
  273. }
  274. int JackCoreAudioIOAdapter::SetupBuffers(int inchannels, int outchannels)
  275. {
  276. jack_log("JackCoreAudioIOAdapter::SetupBuffers: input = %ld output = %ld", inchannels, outchannels);
  277. // Prepare buffers
  278. fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer));
  279. if (fInputData == 0) {
  280. jack_error("Cannot allocate memory for input buffers");
  281. return -1;
  282. }
  283. fInputData->mNumberBuffers = inchannels;
  284. for (int i = 0; i < fCaptureChannels; i++) {
  285. fInputData->mBuffers[i].mNumberChannels = 1;
  286. fInputData->mBuffers[i].mDataByteSize = fBufferSize * sizeof(float);
  287. fInputData->mBuffers[i].mData = malloc(fBufferSize * sizeof(float));
  288. }
  289. return 0;
  290. }
  291. void JackCoreAudioIOAdapter::DisposeBuffers()
  292. {
  293. if (fInputData) {
  294. for (int i = 0; i < fCaptureChannels; i++)
  295. free(fInputData->mBuffers[i].mData);
  296. free(fInputData);
  297. fInputData = 0;
  298. }
  299. }
  300. int JackCoreAudioIOAdapter::OpenAUHAL(bool capturing,
  301. bool playing,
  302. int inchannels,
  303. int outchannels,
  304. int in_nChannels,
  305. int out_nChannels,
  306. jack_nframes_t nframes,
  307. jack_nframes_t samplerate,
  308. bool strict)
  309. {
  310. ComponentResult err1;
  311. UInt32 enableIO;
  312. AudioStreamBasicDescription srcFormat, dstFormat;
  313. jack_log("OpenAUHAL capturing = %ld playing = %ld playing = %ld outchannels = %ld in_nChannels = %ld out_nChannels = %ld ", capturing, playing, inchannels, inchannels, in_nChannels, out_nChannels);
  314. // AUHAL
  315. ComponentDescription cd = {kAudioUnitType_Output, kAudioUnitSubType_HALOutput, kAudioUnitManufacturer_Apple, 0, 0};
  316. Component HALOutput = FindNextComponent(NULL, &cd);
  317. err1 = OpenAComponent(HALOutput, &fAUHAL);
  318. if (err1 != noErr) {
  319. jack_error("Error calling OpenAComponent");
  320. printError(err1);
  321. return -1;
  322. }
  323. err1 = AudioUnitInitialize(fAUHAL);
  324. if (err1 != noErr) {
  325. jack_error("Cannot initialize AUHAL unit");
  326. printError(err1);
  327. return -1;
  328. }
  329. // Start I/O
  330. enableIO = 1;
  331. if (capturing && inchannels > 0) {
  332. jack_log("Setup AUHAL input");
  333. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
  334. if (err1 != noErr) {
  335. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input");
  336. printError(err1);
  337. if (strict)
  338. return -1;
  339. }
  340. }
  341. if (playing && outchannels > 0) {
  342. jack_log("Setup AUHAL output");
  343. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
  344. if (err1 != noErr) {
  345. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output");
  346. printError(err1);
  347. if (strict)
  348. return -1;
  349. }
  350. }
  351. // Setup up choosen device, in both input and output cases
  352. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &fDeviceID, sizeof(AudioDeviceID));
  353. if (err1 != noErr) {
  354. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_CurrentDevice");
  355. printError(err1);
  356. if (strict)
  357. return -1;
  358. }
  359. // Set buffer size
  360. if (capturing && inchannels > 0) {
  361. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, (UInt32*) & nframes, sizeof(UInt32));
  362. if (err1 != noErr) {
  363. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
  364. printError(err1);
  365. if (strict)
  366. return -1;
  367. }
  368. }
  369. if (playing && outchannels > 0) {
  370. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, (UInt32*) & nframes, sizeof(UInt32));
  371. if (err1 != noErr) {
  372. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_MaximumFramesPerSlice");
  373. printError(err1);
  374. if (strict)
  375. return -1;
  376. }
  377. }
  378. // Setup channel map
  379. if (capturing && inchannels > 0 && inchannels < in_nChannels) {
  380. SInt32 chanArr[in_nChannels];
  381. for (int i = 0; i < in_nChannels; i++) {
  382. chanArr[i] = -1;
  383. }
  384. for (int i = 0; i < inchannels; i++) {
  385. chanArr[i] = i;
  386. }
  387. AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Input, 1, chanArr, sizeof(SInt32) * in_nChannels);
  388. if (err1 != noErr) {
  389. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 1");
  390. printError(err1);
  391. }
  392. }
  393. if (playing && outchannels > 0 && outchannels < out_nChannels) {
  394. SInt32 chanArr[out_nChannels];
  395. for (int i = 0; i < out_nChannels; i++) {
  396. chanArr[i] = -1;
  397. }
  398. for (int i = 0; i < outchannels; i++) {
  399. chanArr[i] = i;
  400. }
  401. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_ChannelMap, kAudioUnitScope_Output, 0, chanArr, sizeof(SInt32) * out_nChannels);
  402. if (err1 != noErr) {
  403. jack_error("Error calling AudioUnitSetProperty - kAudioOutputUnitProperty_ChannelMap 0");
  404. printError(err1);
  405. }
  406. }
  407. // Setup stream converters
  408. jack_log("Setup AUHAL input stream converter SR = %ld", samplerate);
  409. srcFormat.mSampleRate = samplerate;
  410. srcFormat.mFormatID = kAudioFormatLinearPCM;
  411. srcFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
  412. srcFormat.mBytesPerPacket = sizeof(float);
  413. srcFormat.mFramesPerPacket = 1;
  414. srcFormat.mBytesPerFrame = sizeof(float);
  415. srcFormat.mChannelsPerFrame = outchannels;
  416. srcFormat.mBitsPerChannel = 32;
  417. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &srcFormat, sizeof(AudioStreamBasicDescription));
  418. if (err1 != noErr) {
  419. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Input");
  420. printError(err1);
  421. }
  422. jack_log("Setup AUHAL output stream converter SR = %ld", samplerate);
  423. dstFormat.mSampleRate = samplerate;
  424. dstFormat.mFormatID = kAudioFormatLinearPCM;
  425. dstFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked | kLinearPCMFormatFlagIsNonInterleaved;
  426. dstFormat.mBytesPerPacket = sizeof(float);
  427. dstFormat.mFramesPerPacket = 1;
  428. dstFormat.mBytesPerFrame = sizeof(float);
  429. dstFormat.mChannelsPerFrame = inchannels;
  430. dstFormat.mBitsPerChannel = 32;
  431. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &dstFormat, sizeof(AudioStreamBasicDescription));
  432. if (err1 != noErr) {
  433. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_StreamFormat kAudioUnitScope_Output");
  434. printError(err1);
  435. }
  436. // Setup callbacks
  437. if (inchannels > 0 && outchannels == 0) {
  438. AURenderCallbackStruct output;
  439. output.inputProc = Render;
  440. output.inputProcRefCon = this;
  441. err1 = AudioUnitSetProperty(fAUHAL, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &output, sizeof(output));
  442. if (err1 != noErr) {
  443. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 1");
  444. printError(err1);
  445. return -1;
  446. }
  447. } else {
  448. AURenderCallbackStruct output;
  449. output.inputProc = Render;
  450. output.inputProcRefCon = this;
  451. err1 = AudioUnitSetProperty(fAUHAL, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &output, sizeof(output));
  452. if (err1 != noErr) {
  453. jack_error("Error calling AudioUnitSetProperty - kAudioUnitProperty_SetRenderCallback 0");
  454. printError(err1);
  455. return -1;
  456. }
  457. }
  458. return 0;
  459. }
  460. void JackCoreAudioIOAdapter::CloseAUHAL()
  461. {
  462. AudioUnitUninitialize(fAUHAL);
  463. CloseComponent(fAUHAL);
  464. }
  465. int JackCoreAudioIOAdapter::Open()
  466. {
  467. OSStatus err;
  468. int in_nChannels = 0;
  469. int out_nChannels = 0;
  470. if (SetupDevices("", "", "", "") < 0)
  471. return -1;
  472. if (SetupChannels(true, true, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, true) < 0)
  473. return -1;
  474. if (SetupBufferSizeAndSampleRate(fBufferSize, fSampleRate) < 0)
  475. return -1;
  476. if (OpenAUHAL(true, true, fCaptureChannels, fPlaybackChannels, in_nChannels, out_nChannels, fBufferSize, fSampleRate, true) < 0)
  477. goto error;
  478. if (SetupBuffers(fCaptureChannels, fPlaybackChannels) < 0)
  479. goto error;
  480. err = AudioOutputUnitStart(fAUHAL);
  481. if (err != noErr)
  482. goto error;
  483. return 0;
  484. error:
  485. Close();
  486. return -1;
  487. }
  488. int JackCoreAudioIOAdapter::Close()
  489. {
  490. AudioOutputUnitStop(fAUHAL);
  491. DisposeBuffers();
  492. CloseAUHAL();
  493. return 0;
  494. }
  495. int JackCoreAudioIOAdapter::SetBufferSize(jack_nframes_t buffer_size)
  496. {
  497. JackIOAdapterInterface::SetBufferSize(buffer_size);
  498. Close();
  499. return Open();
  500. }
  501. }