/[svn]/linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceJack.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/drivers/audio/AudioOutputDeviceJack.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2512 - (show annotations) (download)
Sun Jan 26 17:47:43 2014 UTC (10 years, 2 months ago) by schoenebeck
File size: 18773 byte(s)
* JACK audio driver: return JACK server's current sample rate
  as default value for audio device parameter "SAMPLERATE"
  (fixes #166).
* Bumped version (1.0.0.svn27).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2014 Christian Schoenebeck *
7 * *
8 * This program is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #include "AudioOutputDeviceJack.h"
25 #include "AudioOutputDeviceFactory.h"
26
27 #include <errno.h>
28
29 #if HAVE_JACK
30
31 #ifndef HAVE_JACK_CLIENT_NAME_SIZE
32 #define jack_client_name_size() 33
33 #endif
34
35 namespace LinuxSampler {
36
37 /// number of currently existing JACK audio output devices in LinuxSampler
38 static int existingJackDevices = 0;
39
40 // *************** AudioChannelJack::ParameterName ***************
41 // *
42
43 AudioOutputDeviceJack::AudioChannelJack::ParameterName::ParameterName(AudioChannelJack* pChannel) : AudioChannel::ParameterName(ToString(pChannel->ChannelNr)) {
44 this->pChannel = pChannel;
45 }
46
47 void AudioOutputDeviceJack::AudioChannelJack::ParameterName::OnSetValue(String s) {
48 if (jack_port_set_name(pChannel->hJackPort, s.c_str())) throw AudioOutputException("Failed to rename JACK port");
49 }
50
51
52
53 // *************** AudioChannelJack::ParameterJackBindings ***************
54 // *
55
56 AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::ParameterJackBindings(AudioChannelJack* pChannel) : DeviceRuntimeParameterStrings(std::vector<String>()) {
57 this->pChannel = pChannel;
58 }
59
60 String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Description() {
61 return "Bindings to other JACK clients";
62 }
63
64 bool AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Fix() {
65 return false;
66 }
67
68 std::vector<String> AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::PossibilitiesAsString() {
69 const char** pPortNames = jack_get_ports(pChannel->pDevice->hJackClient, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput);
70 if (!pPortNames) return std::vector<String>();
71 std::vector<String> result;
72 for (int i = 0; pPortNames[i]; i++) result.push_back(pPortNames[i]);
73 free(pPortNames);
74 return result;
75 }
76
77 void AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::OnSetValue(std::vector<String> vS) {
78 String src_name = ((DeviceCreationParameterString*)pChannel->pDevice->Parameters["NAME"])->ValueAsString() + ":" +
79 ((DeviceRuntimeParameterString*)pChannel->Parameters["NAME"])->ValueAsString();
80 // disconnect all current bindings first
81 for (int i = 0; i < Bindings.size(); i++) {
82 String dst_name = Bindings[i];
83 /*int res =*/ jack_disconnect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
84 }
85 // connect new bindings
86 for (int i = 0; i < vS.size(); i++) {
87 String dst_name = vS[i];
88 int res = jack_connect(pChannel->pDevice->hJackClient, src_name.c_str(), dst_name.c_str());
89 if (res == EEXIST) throw AudioOutputException("Jack: Connection to port '" + dst_name + "' already established");
90 else if (res) throw AudioOutputException("Jack: Cannot connect port '" + src_name + "' to port '" + dst_name + "'");
91 }
92 // remember bindings
93 Bindings = vS;
94 }
95
96 String AudioOutputDeviceJack::AudioChannelJack::ParameterJackBindings::Name() {
97 return "JACK_BINDINGS";
98 }
99
100
101
102 // *************** AudioChannelJack ***************
103 // *
104
105 AudioOutputDeviceJack::AudioChannelJack::AudioChannelJack(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) : AudioChannel(ChannelNr, CreateJackPort(ChannelNr, pDevice), pDevice->uiMaxSamplesPerCycle) {
106 this->pDevice = pDevice;
107 this->ChannelNr = ChannelNr;
108 delete Parameters["NAME"];
109 Parameters["NAME"] = new ParameterName(this);
110 Parameters["JACK_BINDINGS"] = new ParameterJackBindings(this);
111 }
112
113 AudioOutputDeviceJack::AudioChannelJack::~AudioChannelJack() {
114 //TODO: delete JACK port
115 }
116
117 float* AudioOutputDeviceJack::AudioChannelJack::CreateJackPort(uint ChannelNr, AudioOutputDeviceJack* pDevice) throw (AudioOutputException) {
118 String port_id = ToString(ChannelNr);
119 hJackPort = jack_port_register(pDevice->hJackClient, port_id.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
120 if (!hJackPort) throw AudioOutputException("Jack: Cannot register Jack output port.");
121 return (float*) jack_port_get_buffer(hJackPort, pDevice->uiMaxSamplesPerCycle);
122 }
123
124 void AudioOutputDeviceJack::AudioChannelJack::UpdateJackBuffer(uint size) {
125 SetBuffer(
126 (float*)jack_port_get_buffer(hJackPort, size)
127 );
128 }
129
130
131
132 // *************** AudioOutputDeviceJack::ParameterName ***************
133 // *
134
135 AudioOutputDeviceJack::ParameterName::ParameterName() : DeviceCreationParameterString() {
136 InitWithDefault(); // use default name
137 }
138
139 AudioOutputDeviceJack::ParameterName::ParameterName(String s) throw (Exception) : DeviceCreationParameterString(s) {
140 }
141
142 String AudioOutputDeviceJack::ParameterName::Description() {
143 return "Arbitrary JACK client name";
144 }
145
146 bool AudioOutputDeviceJack::ParameterName::Fix() {
147 return true;
148 }
149
150 bool AudioOutputDeviceJack::ParameterName::Mandatory() {
151 return false;
152 }
153
154 std::map<String,DeviceCreationParameter*> AudioOutputDeviceJack::ParameterName::DependsAsParameters() {
155 return std::map<String,DeviceCreationParameter*>(); // no dependencies
156 }
157
158 std::vector<String> AudioOutputDeviceJack::ParameterName::PossibilitiesAsString(std::map<String,String> Parameters) {
159 return std::vector<String>();
160 }
161
162 optional<String> AudioOutputDeviceJack::ParameterName::DefaultAsString(std::map<String,String> Parameters) {
163 return (existingJackDevices) ? "LinuxSampler" + ToString(existingJackDevices) : "LinuxSampler";
164 }
165
166 void AudioOutputDeviceJack::ParameterName::OnSetValue(String s) throw (Exception) {
167 // not possible, as parameter is fix
168 }
169
170 String AudioOutputDeviceJack::ParameterName::Name() {
171 return "NAME";
172 }
173
174
175
176 // *************** AudioOutputDeviceJack::ParameterSampleRate ***************
177 // *
178
179 AudioOutputDeviceJack::ParameterSampleRate::ParameterSampleRate() : AudioOutputDevice::ParameterSampleRate() {
180 }
181
182 AudioOutputDeviceJack::ParameterSampleRate::ParameterSampleRate(String s) : AudioOutputDevice::ParameterSampleRate(s) {
183 }
184
185 optional<int> AudioOutputDeviceJack::ParameterSampleRate::DefaultAsInt(std::map<String,String> Parameters) {
186 static int i = 0;
187 // arbitrary JACK client name, that shall not clash with other ones
188 String name = "LinSmPSR" + ToString(i++);
189 #if HAVE_JACK_CLIENT_OPEN
190 jack_client_t* hClient = jack_client_open(name.c_str(), JackNullOption, NULL);
191 #else
192 jack_client_t* hClient = jack_client_new(name.c_str());
193 #endif
194 // Better return "nothing" instead of i.e. 44100 here, so a frontend
195 // like QSampler will not be tempted to pass SAMPLERATE as creation
196 // parameter when creating a new JACK audio device instance.
197 if (!hClient) return optional<int>::nothing;
198 int sampleRate = jack_get_sample_rate(hClient);
199 jack_client_close(hClient);
200 return sampleRate;
201 }
202
203 void AudioOutputDeviceJack::ParameterSampleRate::OnSetValue(int i) throw (Exception) {
204 // nothing to do: the JACK API does currently not allow JACK clients to
205 // change the sample rate
206 }
207
208
209
210 // *************** AudioOutputDeviceJack ***************
211 // *
212
213 /**
214 * Open and initialize connection to the JACK system.
215 *
216 * @param Parameters - optional parameters
217 * @throws AudioOutputException on error
218 * @see AcquireChannels()
219 */
220 AudioOutputDeviceJack::AudioOutputDeviceJack(std::map<String,DeviceCreationParameter*> Parameters) : AudioOutputDevice(Parameters) {
221 pJackClient = JackClient::CreateAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
222 existingJackDevices++;
223 pJackClient->SetAudioOutputDevice(this);
224 hJackClient = pJackClient->hJackClient;
225 uiMaxSamplesPerCycle = jack_get_buffer_size(hJackClient);
226
227 // create audio channels
228 AcquireChannels(((DeviceCreationParameterInt*)Parameters["CHANNELS"])->ValueAsInt());
229
230 // finally activate device if desired
231 if (((DeviceCreationParameterBool*)Parameters["ACTIVE"])->ValueAsBool()) Play();
232 }
233
234 AudioOutputDeviceJack::~AudioOutputDeviceJack() {
235 // destroy jack client if there is no midi device associated with it
236 JackClient::ReleaseAudio(((DeviceCreationParameterString*)Parameters["NAME"])->ValueAsString());
237 existingJackDevices--;
238 }
239
240 /**
241 * This method should not be called directly! It will be called by
242 * libjack to demand transmission of further sample points.
243 */
244 int AudioOutputDeviceJack::Process(uint Samples) {
245 int res;
246
247 // in recent versions of JACK2 and JACk1, we are forced to
248 // re-retrieve the audio buffer pointers in each process period
249 UpdateJackBuffers(Samples);
250
251 if (csIsPlaying.Pop()) {
252 // let all connected engines render 'Samples' sample points
253 res = RenderAudio(Samples);
254 }
255 else {
256 // playback stop by zeroing output buffer(s) and not calling connected sampler engines to render audio
257 res = RenderSilence(Samples);
258 }
259 csIsPlaying.RttDone();
260 return res;
261 }
262
263 void AudioOutputDeviceJack::UpdateJackBuffers(uint size) {
264 for (int i = 0; i < Channels.size(); ++i)
265 static_cast<AudioChannelJack*>(Channels[i])->UpdateJackBuffer(size);
266 }
267
268 float AudioOutputDeviceJack::latency() {
269 if (!hJackClient) return -1;
270 const float size = jack_get_buffer_size(hJackClient);
271 const float rate = jack_get_sample_rate(hJackClient);
272 return size / rate;
273 }
274
275 jack_client_t* AudioOutputDeviceJack::jackClientHandle() {
276 return hJackClient;
277 }
278
279 void AudioOutputDeviceJack::Play() {
280 csIsPlaying.PushAndUnlock(true);
281 }
282
283 bool AudioOutputDeviceJack::IsPlaying() {
284 return csIsPlaying.GetUnsafe();
285 }
286
287 void AudioOutputDeviceJack::Stop() {
288 csIsPlaying.PushAndUnlock(false);
289 }
290
291 AudioChannel* AudioOutputDeviceJack::CreateChannel(uint ChannelNr) {
292 return new AudioChannelJack(ChannelNr, this);
293 }
294
295 uint AudioOutputDeviceJack::MaxSamplesPerCycle() {
296 return jack_get_buffer_size(hJackClient);
297 }
298
299 uint AudioOutputDeviceJack::SampleRate() {
300 return jack_get_sample_rate(hJackClient);
301 }
302
303 void AudioOutputDeviceJack::addListener(JackListener* listener) {
304 pJackClient->addListener(listener);
305 }
306
307 String AudioOutputDeviceJack::Name() {
308 return "JACK";
309 }
310
311 String AudioOutputDeviceJack::Driver() {
312 return Name();
313 }
314
315 String AudioOutputDeviceJack::Description() {
316 return "JACK Audio Connection Kit";
317 }
318
319 String AudioOutputDeviceJack::Version() {
320 String s = "$Revision$";
321 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
322 }
323
324
325
326 // *************** JackClient ***************
327 // *
328
329 // libjack callback functions
330
331 int linuxsampler_libjack_process_callback(jack_nframes_t nframes, void* arg) {
332 return static_cast<JackClient*>(arg)->Process(nframes);
333 }
334
335 #if HAVE_JACK_ON_INFO_SHUTDOWN
336 void JackClient::libjackShutdownCallback(jack_status_t code, const char* reason, void *arg)
337 #else
338 void JackClient::libjackShutdownCallback(void *arg)
339 #endif
340 {
341 JackClient* jackClient = static_cast<JackClient*>(arg);
342 jackClient->Stop();
343 fprintf(stderr, "Jack: Jack server shutdown, exiting.\n");
344 for (int i = 0; i < jackClient->jackListeners.size(); ++i) {
345 JackListener* listener = jackClient->jackListeners[i];
346 #if HAVE_JACK_ON_INFO_SHUTDOWN
347 listener->onJackShutdown(code, reason);
348 #else
349 listener->onJackShutdown(JackFailure, "unknown");
350 #endif
351 }
352 }
353
354 int JackClient::libjackSampleRateCallback(jack_nframes_t nframes, void *arg) {
355 JackClient* client = static_cast<JackClient*>(arg);
356 const config_t& config = client->ConfigReader.Lock();
357 if (config.AudioDevice)
358 config.AudioDevice->ReconnectAll();
359 client->ConfigReader.Unlock();
360 return 0;
361 }
362
363 int JackClient::libjackBufferSizeCallback(jack_nframes_t nframes, void *arg) {
364 dmsg(1,("libjackBufferSizeCallback(%d)\n",nframes));
365 JackClient* client = static_cast<JackClient*>(arg);
366 const config_t& config = client->ConfigReader.Lock();
367 if (config.AudioDevice) {
368 config.AudioDevice->UpdateJackBuffers(nframes);
369 config.AudioDevice->ReconnectAll();
370 }
371 client->ConfigReader.Unlock();
372 return 0;
373 }
374
375 void JackClient::addListener(JackListener* listener) {
376 jackListeners.push_back(listener);
377 }
378
379 std::map<String, JackClient*> JackClient::Clients;
380
381 int JackClient::Process(uint Samples) {
382 const config_t& config = ConfigReader.Lock();
383 #if HAVE_JACK_MIDI
384 if (config.MidiDevice) config.MidiDevice->Process(Samples);
385 #endif
386 int res = config.AudioDevice ? config.AudioDevice->Process(Samples) : 0;
387 ConfigReader.Unlock();
388 return res;
389 }
390
391 void JackClient::Stop() {
392 const config_t& config = ConfigReader.Lock();
393 if (config.AudioDevice) config.AudioDevice->Stop();
394 ConfigReader.Unlock();
395 }
396
397 JackClient::JackClient(String Name) : ConfigReader(Config) {
398 {
399 config_t& config = Config.GetConfigForUpdate();
400 config.AudioDevice = 0;
401 #if HAVE_JACK_MIDI
402 config.MidiDevice = 0;
403 #endif
404 }
405 {
406 config_t& config = Config.SwitchConfig();
407 config.AudioDevice = 0;
408 #if HAVE_JACK_MIDI
409 config.MidiDevice = 0;
410 #endif
411 }
412 audio = midi = false;
413 if (Name.size() >= jack_client_name_size())
414 throw Exception("JACK client name too long");
415 #if HAVE_JACK_CLIENT_OPEN
416 hJackClient = jack_client_open(Name.c_str(), JackNullOption, NULL);
417 #else
418 hJackClient = jack_client_new(Name.c_str());
419 #endif
420 if (!hJackClient)
421 throw Exception("Seems Jack server is not running.");
422 jack_set_process_callback(hJackClient, linuxsampler_libjack_process_callback, this);
423 #if HAVE_JACK_ON_INFO_SHUTDOWN
424 jack_on_info_shutdown(hJackClient, libjackShutdownCallback, this);
425 #else
426 jack_on_shutdown(hJackClient, libjackShutdownCallback, this);
427 #endif
428 jack_set_buffer_size_callback(hJackClient, libjackBufferSizeCallback, this);
429 jack_set_sample_rate_callback(hJackClient, libjackSampleRateCallback, this);
430
431 if (jack_activate(hJackClient))
432 throw Exception("Jack: Cannot activate Jack client.");
433 }
434
435 JackClient::~JackClient() {
436 jack_client_close(hJackClient);
437 }
438
439 void JackClient::SetAudioOutputDevice(AudioOutputDeviceJack* device) {
440 Config.GetConfigForUpdate().AudioDevice = device;
441 Config.SwitchConfig().AudioDevice = device;
442 }
443
444 #if HAVE_JACK_MIDI
445 void JackClient::SetMidiInputDevice(MidiInputDeviceJack* device) {
446 Config.GetConfigForUpdate().MidiDevice = device;
447 Config.SwitchConfig().MidiDevice = device;
448 }
449 #endif
450
451 JackClient* JackClient::CreateAudio(String Name) { // static
452 JackClient* client;
453 std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
454 if (it == Clients.end()) {
455 client = new JackClient(Name);
456 Clients[Name] = client;
457 } else {
458 client = it->second;
459 if (client->audio) throw Exception("Jack audio device '" + Name + "' already exists");
460 }
461 client->audio = true;
462 return client;
463 }
464
465 JackClient* JackClient::CreateMidi(String Name) { // static
466 JackClient* client;
467 std::map<String, JackClient*>::const_iterator it = Clients.find(Name);
468 if (it == Clients.end()) {
469 client = new JackClient(Name);
470 Clients[Name] = client;
471 } else {
472 client = it->second;
473 if (client->midi) throw Exception("Jack MIDI device '" + Name + "' already exists");
474 }
475 client->midi = true;
476 return client;
477 }
478
479 void JackClient::ReleaseAudio(String Name) { // static
480 JackClient* client = Clients[Name];
481 client->SetAudioOutputDevice(0);
482 client->audio = false;
483 if (!client->midi) {
484 Clients.erase(Name);
485 delete client;
486 }
487 }
488
489 void JackClient::ReleaseMidi(String Name) { // static
490 JackClient* client = Clients[Name];
491 #if HAVE_JACK_MIDI
492 client->SetMidiInputDevice(0);
493 #endif
494 client->midi = false;
495 if (!client->audio) {
496 Clients.erase(Name);
497 delete client;
498 }
499 }
500
501 } // namespace LinuxSampler
502
503 #endif // HAVE_JACK

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC