Revision 1:b5bcad8e7803 JackDevice

View differences:

JackDevice/ContextJack.cpp
1
/*
2
 Copyright (c) 2015, The Cinder Project
3

  
4
 This code is intended to be used with the Cinder C++ library, http://libcinder.org
5

  
6
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
7
 the following conditions are met:
8

  
9
    * Redistributions of source code must retain the above copyright notice, this list of conditions and
10
	the following disclaimer.
11
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
12
	the following disclaimer in the documentation and/or other materials provided with the distribution.
13

  
14
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
15
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
16
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
17
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
18
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21
 POSSIBILITY OF SUCH DAMAGE.
22
*/
23

  
24
#include "cinder/audio/linux/ContextJack.h"
25
#include "cinder/audio/Exception.h"
26

  
27
namespace cinder { namespace audio { namespace linux {
28

  
29
inline void zeroJackPort( jack_port_t *port, jack_nframes_t nframes )
30
{   
31
  // memset(port, 0, sizeof(jack_default_audio_sample_t) * nframes); 
32
}
33

  
34
inline void copyToJackPort(jack_port_t *port, float *source, jack_nframes_t nframes )
35
{
36
    // dest, source, n 
37
    jack_default_audio_sample_t *out;
38
    out = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes );
39

  
40
    memcpy( out, source, sizeof(jack_default_audio_sample_t) * nframes ) ;
41
}
42

  
43
inline void copyFromJackPort(jack_port_t *port, float *dest, jack_nframes_t nframes )
44
{
45
    // dest, source, n 
46
    jack_default_audio_sample_t *in;
47
    in = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes );
48

  
49
    memcpy( dest, in, sizeof(jack_default_audio_sample_t) * nframes ) ;
50
}
51

  
52

  
53
int OutputDeviceNodeJack::jackCallback(jack_nframes_t nframes, void* userData)
54
{
55
	RenderData *renderData = static_cast<RenderData *>( userData );
56

  
57
	OutputDeviceNodeJack *outputDeviceNode = static_cast<OutputDeviceNodeJack *>( renderData->outputNode );
58

  
59
	auto ctx = renderData->outputNode->getContext();
60
	if( ! ctx ) {
61
        for( size_t chan = 0; chan < 2; chan++)
62
            // FIXME segfault at shutdown 
63
		    zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes );
64

  
65
		return 0;
66
	}
67

  
68
	std::lock_guard<std::mutex> lock( ctx->getMutex() );
69
    
70
	// verify associated context still exists, which may not be true if we blocked in ~Context() and were then deallocated.
71
	ctx = renderData->outputNode->getContext();
72
	if( ! ctx ) {
73

  
74
        for( size_t chan = 0; chan < 2; chan++)
75
		    zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes );
76

  
77
		return 0;
78
	}
79

  
80

  
81
	Buffer *internalBuffer = outputDeviceNode->getInternalBuffer();
82
	internalBuffer->zero();
83

  
84
	ctx->preProcess();
85
	outputDeviceNode->pullInputs( internalBuffer );
86
    
87
	// if clip detection is enabled and buffer clipped, silence it
88
	if( false && outputDeviceNode->checkNotClipping() ){
89
        for( size_t chan = 0; chan < 2; chan++)
90
		    zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes );
91
	} 
92
    else {
93
        for( size_t chan = 0; chan < 2; chan++)
94
            copyToJackPort( outputDeviceNode->mOutputPorts[chan], internalBuffer->getChannel( chan ), nframes  );
95
    }
96

  
97
	ctx->postProcess();
98

  
99
    return 0;
100
}
101

  
102
inline void OutputDeviceNodeJack::setInput( InputDeviceNodeRef inputDeviceNode) 
103
{
104
    mInputDeviceNode = std::static_pointer_cast<InputDeviceNodeJack>(inputDeviceNode);
105
}
106

  
107
ContextJack::ContextJack()
108
{
109

  
110
}
111

  
112
ContextJack::~ContextJack()
113
{
114

  
115
}
116

  
117

  
118
OutputDeviceNodeRef	ContextJack::createOutputDeviceNode( const DeviceRef &device, const Node::Format &format )
119
{
120
	
121
    if( mOutputDeviceNode  == nullptr ) {
122
        auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() );
123

  
124
        mOutputDeviceNode = makeNode( new OutputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ;
125

  
126
        if( mInputDeviceNode != nullptr){
127
            auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode );
128
            castedOutputDeviceNode->setInput( mInputDeviceNode );   
129
        }
130
    }
131

  
132
	return mOutputDeviceNode;
133
}
134

  
135
InputDeviceNodeRef ContextJack::createInputDeviceNode( const DeviceRef &device, const Node::Format &format  )
136
{
137
    if( mInputDeviceNode  == nullptr ) {
138
        auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() );
139

  
140
        mInputDeviceNode = makeNode( new InputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ;
141

  
142
        if( mOutputDeviceNode != nullptr){
143
            auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode );
144
            castedOutputDeviceNode->setInput( mInputDeviceNode );   
145
        }
146
    }
147

  
148
	return mInputDeviceNode;
149
}
150

  
151

  
152
// OutputDeviceNodeJack 
153

  
154
OutputDeviceNodeJack::OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ):
155
    OutputDeviceNode( device, format),
156
    mCinderContext( context )
157
{
158
}
159

  
160
void OutputDeviceNodeJack::initialize()
161
{
162

  
163
    const char *client_name = "Collidoscope";
164
    const char *server_name = NULL;
165
    jack_options_t options = JackNullOption;
166
    jack_status_t status;
167

  
168
    // connect to JAck server 
169
    mClient = jack_client_open (client_name, options, &status, server_name);
170
    if( mClient == NULL){
171

  
172
        std::string msg = "jack_client_open() failed. "; 
173
        if(status & JackServerFailed) 
174
            msg += "Unable to connect to Jack server";
175

  
176
        throw cinder::audio::AudioContextExc(msg);
177
    }
178

  
179
    
180
    mRenderData.outputNode = this;
181
    mRenderData.inputNode = mInputDeviceNode.get();
182
    CI_ASSERT(mInputDeviceNode != nullptr);
183
    mRenderData.context = static_cast<ContextJack *>( getContext().get() );
184

  
185
    // install callback
186
    jack_set_process_callback (mClient, jackCallback, &mRenderData );
187

  
188
    // jack shutdown ? 
189
    
190

  
191
    // setup output ports 
192
    mOutputPorts[0] = jack_port_register (mClient, "output1",
193
                       JACK_DEFAULT_AUDIO_TYPE,
194
                       JackPortIsOutput, 0);
195
    
196
    mOutputPorts[1] = jack_port_register (mClient, "output2",
197
                       JACK_DEFAULT_AUDIO_TYPE,
198
                       JackPortIsOutput, 0);
199
    
200
     if ((mOutputPorts[0] == NULL) || (mOutputPorts[0] == NULL)) {
201
        throw cinder::audio::AudioContextExc("no more JACK ports available");
202
     }
203

  
204
    // setup input ports 
205
    mInputDeviceNode->mInputPorts[0] = jack_port_register (mClient, "input1",
206
                       JACK_DEFAULT_AUDIO_TYPE,
207
                       JackPortIsInput, 0);
208

  
209
    mInputDeviceNode->mInputPorts[1] = jack_port_register (mClient, "input2",
210
                       JACK_DEFAULT_AUDIO_TYPE,
211
                       JackPortIsInput, 0);
212

  
213

  
214
    /* Tell the JACK server that we are ready to roll.  Our callback will start running now. */
215
    if (jack_activate (mClient)) {
216
        throw cinder::audio::AudioContextExc("cannot activate client");
217
    }
218

  
219
    // connect input ports to physical device (microphones)
220
    const char **mikePorts = jack_get_ports (mClient, NULL, NULL,
221
		JackPortIsPhysical|JackPortIsOutput);
222

  
223
	if (mikePorts == NULL) {
224
        throw cinder::audio::AudioContextExc("no physical input ports available");
225
	}
226

  
227
	if (jack_connect (mClient,  mikePorts[0], jack_port_name (mInputDeviceNode->mInputPorts[0]))) {
228
        throw cinder::audio::AudioContextExc("cannot connect input port 0");
229
	}
230

  
231
	if (jack_connect (mClient, mikePorts[1], jack_port_name( mInputDeviceNode->mInputPorts[1]) )) {
232
        throw cinder::audio::AudioContextExc("cannot connect input port 1");
233
	}
234

  
235
    // connect output ports to physical device (audio out )
236
    const char **speakerPorts = jack_get_ports (mClient, NULL, NULL,
237
				JackPortIsPhysical|JackPortIsInput);
238

  
239
	if (speakerPorts == NULL) {
240
        throw cinder::audio::AudioContextExc("no physical output ports available");
241
	}
242

  
243
	if (jack_connect (mClient, jack_port_name (mOutputPorts[0]), speakerPorts[0])) {
244
        throw cinder::audio::AudioContextExc("cannot connect output port 0");
245
	}
246

  
247
	if (jack_connect (mClient, jack_port_name (mOutputPorts[1]), speakerPorts[1])) {
248
        throw cinder::audio::AudioContextExc("cannot connect output port 1");
249
	}
250

  
251
	jack_free( mikePorts );
252
	jack_free( speakerPorts );
253
}
254

  
255

  
256
void OutputDeviceNodeJack::uninitialize()
257
{
258
    jack_client_close( mClient );
259
}
260

  
261
void OutputDeviceNodeJack::enableProcessing()
262
{
263
}
264

  
265
void OutputDeviceNodeJack::disableProcessing()
266
{
267
}
268

  
269

  
270
//-------------------------- InputDeviceNodeJack -------------------------------
271

  
272

  
273
InputDeviceNodeJack::InputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ):
274
    InputDeviceNode( device, format)
275
{
276
}
277

  
278
void InputDeviceNodeJack::initialize() 
279
{
280
}
281

  
282
void InputDeviceNodeJack::uninitialize()
283
{
284
}
285

  
286
void InputDeviceNodeJack::enableProcessing()
287
{
288
}
289

  
290
void InputDeviceNodeJack::disableProcessing()
291
{
292
}
293

  
294
void InputDeviceNodeJack::process( Buffer *buffer )
295
{
296
    for( size_t chan = 0; chan < 2; chan++){
297
       copyFromJackPort(mInputPorts[chan], buffer->getChannel( chan ), buffer->getNumFrames() ); 
298
    }
299
}
300

  
301
} } } // namespace cinder::audio::linux
1
/*
2
 Copyright (c) 2015, The Cinder Project
3

  
4
 This code is intended to be used with the Cinder C++ library, http://libcinder.org
5

  
6
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
7
 the following conditions are met:
8

  
9
    * Redistributions of source code must retain the above copyright notice, this list of conditions and
10
	the following disclaimer.
11
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
12
	the following disclaimer in the documentation and/or other materials provided with the distribution.
13

  
14
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
15
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
16
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
17
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
18
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21
 POSSIBILITY OF SUCH DAMAGE.
22
*/
23

  
24
#include "cinder/audio/linux/ContextJack.h"
25
#include "cinder/audio/Exception.h"
26

  
27
namespace cinder { namespace audio { namespace linux {
28

  
29
inline void zeroJackPort( jack_port_t *port, jack_nframes_t nframes )
30
{   
31
  // memset(port, 0, sizeof(jack_default_audio_sample_t) * nframes); 
32
}
33

  
34
inline void copyToJackPort(jack_port_t *port, float *source, jack_nframes_t nframes )
35
{
36
    // dest, source, n 
37
    jack_default_audio_sample_t *out;
38
    out = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes );
39

  
40
    memcpy( out, source, sizeof(jack_default_audio_sample_t) * nframes ) ;
41
}
42

  
43
inline void copyFromJackPort(jack_port_t *port, float *dest, jack_nframes_t nframes )
44
{
45
    // dest, source, n 
46
    jack_default_audio_sample_t *in;
47
    in = (jack_default_audio_sample_t *) jack_port_get_buffer( port, nframes );
48

  
49
    memcpy( dest, in, sizeof(jack_default_audio_sample_t) * nframes ) ;
50
}
51

  
52

  
53
int OutputDeviceNodeJack::jackCallback(jack_nframes_t nframes, void* userData)
54
{
55
	RenderData *renderData = static_cast<RenderData *>( userData );
56

  
57
	OutputDeviceNodeJack *outputDeviceNode = static_cast<OutputDeviceNodeJack *>( renderData->outputNode );
58

  
59
	auto ctx = renderData->outputNode->getContext();
60
	if( ! ctx ) {
61
        for( size_t chan = 0; chan < 2; chan++)
62
            // FIXME segfault at shutdown 
63
		    zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes );
64

  
65
		return 0;
66
	}
67

  
68
	std::lock_guard<std::mutex> lock( ctx->getMutex() );
69
    
70
	// verify associated context still exists, which may not be true if we blocked in ~Context() and were then deallocated.
71
	ctx = renderData->outputNode->getContext();
72
	if( ! ctx ) {
73

  
74
        for( size_t chan = 0; chan < 2; chan++)
75
		    zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes );
76

  
77
		return 0;
78
	}
79

  
80

  
81
	Buffer *internalBuffer = outputDeviceNode->getInternalBuffer();
82
	internalBuffer->zero();
83

  
84
	ctx->preProcess();
85
	outputDeviceNode->pullInputs( internalBuffer );
86
    
87
	// if clip detection is enabled and buffer clipped, silence it
88
	if( false && outputDeviceNode->checkNotClipping() ){
89
        for( size_t chan = 0; chan < 2; chan++)
90
		    zeroJackPort( outputDeviceNode->mOutputPorts[chan], nframes );
91
	} 
92
    else {
93
        for( size_t chan = 0; chan < 2; chan++)
94
            copyToJackPort( outputDeviceNode->mOutputPorts[chan], internalBuffer->getChannel( chan ), nframes  );
95
    }
96

  
97
	ctx->postProcess();
98

  
99
    return 0;
100
}
101

  
102
inline void OutputDeviceNodeJack::setInput( InputDeviceNodeRef inputDeviceNode) 
103
{
104
    mInputDeviceNode = std::static_pointer_cast<InputDeviceNodeJack>(inputDeviceNode);
105
}
106

  
107
ContextJack::ContextJack()
108
{
109

  
110
}
111

  
112
ContextJack::~ContextJack()
113
{
114

  
115
}
116

  
117

  
118
OutputDeviceNodeRef	ContextJack::createOutputDeviceNode( const DeviceRef &device, const Node::Format &format )
119
{
120
	
121
    if( mOutputDeviceNode  == nullptr ) {
122
        auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() );
123

  
124
        mOutputDeviceNode = makeNode( new OutputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ;
125

  
126
        if( mInputDeviceNode != nullptr){
127
            auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode );
128
            castedOutputDeviceNode->setInput( mInputDeviceNode );   
129
        }
130
    }
131

  
132
	return mOutputDeviceNode;
133
}
134

  
135
InputDeviceNodeRef ContextJack::createInputDeviceNode( const DeviceRef &device, const Node::Format &format  )
136
{
137
    if( mInputDeviceNode  == nullptr ) {
138
        auto thisRef = std::static_pointer_cast<ContextJack>( shared_from_this() );
139

  
140
        mInputDeviceNode = makeNode( new InputDeviceNodeJack( device, Node::Format().channels(2), thisRef ) ) ;
141

  
142
        if( mOutputDeviceNode != nullptr){
143
            auto castedOutputDeviceNode = std::static_pointer_cast<OutputDeviceNodeJack>( mOutputDeviceNode );
144
            castedOutputDeviceNode->setInput( mInputDeviceNode );   
145
        }
146
    }
147

  
148
	return mInputDeviceNode;
149
}
150

  
151

  
152
// OutputDeviceNodeJack 
153

  
154
OutputDeviceNodeJack::OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ):
155
    OutputDeviceNode( device, format),
156
    mCinderContext( context )
157
{
158
}
159

  
160
void OutputDeviceNodeJack::initialize()
161
{
162

  
163
    const char *client_name = "Collidoscope";
164
    const char *server_name = NULL;
165
    jack_options_t options = JackNullOption;
166
    jack_status_t status;
167

  
168
    // connect to JAck server 
169
    mClient = jack_client_open (client_name, options, &status, server_name);
170
    if( mClient == NULL){
171

  
172
        std::string msg = "jack_client_open() failed. "; 
173
        if(status & JackServerFailed) 
174
            msg += "Unable to connect to Jack server";
175

  
176
        throw cinder::audio::AudioContextExc(msg);
177
    }
178

  
179
    
180
    mRenderData.outputNode = this;
181
    mRenderData.inputNode = mInputDeviceNode.get();
182
    CI_ASSERT(mInputDeviceNode != nullptr);
183
    mRenderData.context = static_cast<ContextJack *>( getContext().get() );
184

  
185
    // install callback
186
    jack_set_process_callback (mClient, jackCallback, &mRenderData );
187

  
188
    // jack shutdown ? 
189
    
190

  
191
    // setup output ports 
192
    mOutputPorts[0] = jack_port_register (mClient, "output1",
193
                       JACK_DEFAULT_AUDIO_TYPE,
194
                       JackPortIsOutput, 0);
195
    
196
    mOutputPorts[1] = jack_port_register (mClient, "output2",
197
                       JACK_DEFAULT_AUDIO_TYPE,
198
                       JackPortIsOutput, 0);
199
    
200
     if ((mOutputPorts[0] == NULL) || (mOutputPorts[0] == NULL)) {
201
        throw cinder::audio::AudioContextExc("no more JACK ports available");
202
     }
203

  
204
    // setup input ports 
205
    mInputDeviceNode->mInputPorts[0] = jack_port_register (mClient, "input1",
206
                       JACK_DEFAULT_AUDIO_TYPE,
207
                       JackPortIsInput, 0);
208

  
209
    mInputDeviceNode->mInputPorts[1] = jack_port_register (mClient, "input2",
210
                       JACK_DEFAULT_AUDIO_TYPE,
211
                       JackPortIsInput, 0);
212

  
213

  
214
    /* Tell the JACK server that we are ready to roll.  Our callback will start running now. */
215
    if (jack_activate (mClient)) {
216
        throw cinder::audio::AudioContextExc("cannot activate client");
217
    }
218

  
219
    // connect input ports to physical device (microphones)
220
    const char **mikePorts = jack_get_ports (mClient, NULL, NULL,
221
		JackPortIsPhysical|JackPortIsOutput);
222

  
223
	if (mikePorts == NULL) {
224
        throw cinder::audio::AudioContextExc("no physical input ports available");
225
	}
226

  
227
	if (jack_connect (mClient,  mikePorts[0], jack_port_name (mInputDeviceNode->mInputPorts[0]))) {
228
        throw cinder::audio::AudioContextExc("cannot connect input port 0");
229
	}
230

  
231
	if (jack_connect (mClient, mikePorts[1], jack_port_name( mInputDeviceNode->mInputPorts[1]) )) {
232
        throw cinder::audio::AudioContextExc("cannot connect input port 1");
233
	}
234

  
235
    // connect output ports to physical device (audio out )
236
    const char **speakerPorts = jack_get_ports (mClient, NULL, NULL,
237
				JackPortIsPhysical|JackPortIsInput);
238

  
239
	if (speakerPorts == NULL) {
240
        throw cinder::audio::AudioContextExc("no physical output ports available");
241
	}
242

  
243
	if (jack_connect (mClient, jack_port_name (mOutputPorts[0]), speakerPorts[0])) {
244
        throw cinder::audio::AudioContextExc("cannot connect output port 0");
245
	}
246

  
247
	if (jack_connect (mClient, jack_port_name (mOutputPorts[1]), speakerPorts[1])) {
248
        throw cinder::audio::AudioContextExc("cannot connect output port 1");
249
	}
250

  
251
	jack_free( mikePorts );
252
	jack_free( speakerPorts );
253
}
254

  
255

  
256
void OutputDeviceNodeJack::uninitialize()
257
{
258
    jack_client_close( mClient );
259
}
260

  
261
void OutputDeviceNodeJack::enableProcessing()
262
{
263
}
264

  
265
void OutputDeviceNodeJack::disableProcessing()
266
{
267
}
268

  
269

  
270
//-------------------------- InputDeviceNodeJack -------------------------------
271

  
272

  
273
InputDeviceNodeJack::InputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context ):
274
    InputDeviceNode( device, format)
275
{
276
}
277

  
278
void InputDeviceNodeJack::initialize() 
279
{
280
}
281

  
282
void InputDeviceNodeJack::uninitialize()
283
{
284
}
285

  
286
void InputDeviceNodeJack::enableProcessing()
287
{
288
}
289

  
290
void InputDeviceNodeJack::disableProcessing()
291
{
292
}
293

  
294
void InputDeviceNodeJack::process( Buffer *buffer )
295
{
296
    for( size_t chan = 0; chan < 2; chan++){
297
       copyFromJackPort(mInputPorts[chan], buffer->getChannel( chan ), buffer->getNumFrames() ); 
298
    }
299
}
300

  
301
} } } // namespace cinder::audio::linux
JackDevice/ContextJack.h
1
/*
2
 Copyright (c) 2015, The Cinder Project
3

  
4
 This code is intended to be used with the Cinder C++ library, http://libcinder.org
5

  
6
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
7
 the following conditions are met:
8

  
9
    * Redistributions of source code must retain the above copyright notice, this list of conditions and
10
	the following disclaimer.
11
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
12
	the following disclaimer in the documentation and/or other materials provided with the distribution.
13

  
14
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
15
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
16
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
17
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
18
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21
 POSSIBILITY OF SUCH DAMAGE.
22
*/
23

  
24
#pragma once
25

  
26
#include "cinder/audio/Context.h" 
27
#include <jack/jack.h>
28

  
29
namespace cinder { namespace audio { namespace linux {
30

  
31
class ContextJack;
32
class InputDeviceNodeJack;
33

  
34
class OutputDeviceNodeJack : public OutputDeviceNode {
35
  public:
36
	OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context );
37

  
38
    void setInput(InputDeviceNodeRef inputDeviceNode);
39

  
40
  protected:
41
	void initialize()				override;
42
	void uninitialize()				override;
43
	void enableProcessing()			override;
44
	void disableProcessing()		override;
45
	bool supportsProcessInPlace() const	override	{ return false; }
46

  
47
  private:
48
    static int jackCallback(jack_nframes_t nframes, void* userData);
49

  
50

  
51
	void renderToBufferFromInputs();
52

  
53
    struct RenderData{
54
        RenderData() : inputNode(nullptr), outputNode(nullptr), context(nullptr){}
55
        ~RenderData() { inputNode = nullptr; outputNode = nullptr;  context = nullptr; }
56
        Node* outputNode;
57
        Node* inputNode;
58
        ContextJack* context;
59
    } mRenderData;
60

  
61
    std::weak_ptr<ContextJack>  mCinderContext;
62

  
63
	jack_client_t *mClient;
64

  
65
    std::array< jack_port_t*, 2 > mOutputPorts;
66

  
67
    std::shared_ptr<InputDeviceNodeJack> mInputDeviceNode;
68
};
69

  
70
class InputDeviceNodeJack : public InputDeviceNode {
71
  friend OutputDeviceNodeJack;
72

  
73
  public:
74
	InputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context );
75

  
76
  protected:
77
	void initialize()				override;
78
	void uninitialize()				override;
79
	void enableProcessing()			override;
80
	void disableProcessing()		override;
81
	void process( Buffer *buffer )	override;
82

  
83
  private:
84
    std::array< jack_port_t*, 2 > mInputPorts;
85
};
86

  
87
class ContextJack : public Context {
88
  public:
89
	ContextJack();
90
	virtual ~ContextJack();
91
    
92

  
93
	OutputDeviceNodeRef	createOutputDeviceNode( const DeviceRef &device, const Node::Format &format = Node::Format() ) override;
94
	InputDeviceNodeRef	createInputDeviceNode( const DeviceRef &device, const Node::Format &format = Node::Format()  ) override;
95

  
96
    OutputDeviceNodeRef	mOutputDeviceNode;
97
    InputDeviceNodeRef	mInputDeviceNode;
98

  
99

  
100
  private:
101
};	
102

  
103
} } } // namespace cinder::audio::linux
1
/*
2
 Copyright (c) 2015, The Cinder Project
3

  
4
 This code is intended to be used with the Cinder C++ library, http://libcinder.org
5

  
6
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
7
 the following conditions are met:
8

  
9
    * Redistributions of source code must retain the above copyright notice, this list of conditions and
10
	the following disclaimer.
11
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
12
	the following disclaimer in the documentation and/or other materials provided with the distribution.
13

  
14
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
15
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
16
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
17
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
18
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21
 POSSIBILITY OF SUCH DAMAGE.
22
*/
23

  
24
#pragma once
25

  
26
#include "cinder/audio/Context.h" 
27
#include <jack/jack.h>
28

  
29
namespace cinder { namespace audio { namespace linux {
30

  
31
class ContextJack;
32
class InputDeviceNodeJack;
33

  
34
class OutputDeviceNodeJack : public OutputDeviceNode {
35
  public:
36
	OutputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context );
37

  
38
    void setInput(InputDeviceNodeRef inputDeviceNode);
39

  
40
  protected:
41
	void initialize()				override;
42
	void uninitialize()				override;
43
	void enableProcessing()			override;
44
	void disableProcessing()		override;
45
	bool supportsProcessInPlace() const	override	{ return false; }
46

  
47
  private:
48
    static int jackCallback(jack_nframes_t nframes, void* userData);
49

  
50

  
51
	void renderToBufferFromInputs();
52

  
53
    struct RenderData{
54
        RenderData() : inputNode(nullptr), outputNode(nullptr), context(nullptr){}
55
        ~RenderData() { inputNode = nullptr; outputNode = nullptr;  context = nullptr; }
56
        Node* outputNode;
57
        Node* inputNode;
58
        ContextJack* context;
59
    } mRenderData;
60

  
61
    std::weak_ptr<ContextJack>  mCinderContext;
62

  
63
	jack_client_t *mClient;
64

  
65
    std::array< jack_port_t*, 2 > mOutputPorts;
66

  
67
    std::shared_ptr<InputDeviceNodeJack> mInputDeviceNode;
68
};
69

  
70
class InputDeviceNodeJack : public InputDeviceNode {
71
  friend OutputDeviceNodeJack;
72

  
73
  public:
74
	InputDeviceNodeJack( const DeviceRef &device, const Format &format, const std::shared_ptr<ContextJack> &context );
75

  
76
  protected:
77
	void initialize()				override;
78
	void uninitialize()				override;
79
	void enableProcessing()			override;
80
	void disableProcessing()		override;
81
	void process( Buffer *buffer )	override;
82

  
83
  private:
84
    std::array< jack_port_t*, 2 > mInputPorts;
85
};
86

  
87
class ContextJack : public Context {
88
  public:
89
	ContextJack();
90
	virtual ~ContextJack();
91
    
92

  
93
	OutputDeviceNodeRef	createOutputDeviceNode( const DeviceRef &device, const Node::Format &format = Node::Format() ) override;
94
	InputDeviceNodeRef	createInputDeviceNode( const DeviceRef &device, const Node::Format &format = Node::Format()  ) override;
95

  
96
    OutputDeviceNodeRef	mOutputDeviceNode;
97
    InputDeviceNodeRef	mInputDeviceNode;
98

  
99

  
100
  private:
101
};	
102

  
103
} } } // namespace cinder::audio::linux
JackDevice/DeviceManagerJack.cpp
1
/*
2
 Copyright (c) 2015, The Cinder Project
3

  
4
 This code is intended to be used with the Cinder C++ library, http://libcinder.org
5

  
6
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
7
 the following conditions are met:
8

  
9
    * Redistributions of source code must retain the above copyright notice, this list of conditions and
10
	
11
    the following disclaimer.
12
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
13
	the following disclaimer in the documentation and/or other materials provided with the distribution.
14

  
15
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
16
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
17
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
18
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
19
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22
 POSSIBILITY OF SUCH DAMAGE.
23
*/
24

  
25
#include "cinder/audio/linux/DeviceManagerJack.h"
26
#include "cinder/audio/Exception.h"
27
#include <jack/jack.h>
28

  
29

  
30
namespace cinder { namespace audio { namespace linux {
31

  
32
DeviceManagerJack::DeviceManagerJack() 
33
{
34

  
35
    mDevices.push_back( addDevice("JackIn") );
36
    mDevices.push_back( addDevice("JackOut") );
37

  
38
    jack_status_t status;
39
    
40
	jack_client_t *client = jack_client_open ("device info", JackNullOption, &status, NULL);
41
    if( client == NULL){
42

  
43
        std::string msg = "jack_client_open() failed. "; 
44
        if(status & JackServerFailed) 
45
            msg += "Unable to connect to Jack server";
46

  
47
        throw cinder::audio::AudioContextExc(msg);
48
    }
49

  
50
    mSampleRate = jack_get_sample_rate( client );
51
    mBufferSize = jack_get_buffer_size( client );
52

  
53
    jack_client_close( client );
54
}
55

  
56
DeviceManagerJack::~DeviceManagerJack()
57
{
58
	
59
}
60

  
61
const std::vector<DeviceRef>& DeviceManagerJack::getDevices()
62
{
63
   return mDevices;
64
}
65

  
66
DeviceRef DeviceManagerJack::getDefaultOutput()
67
{
68
    return mDevices[1];
69
}
70

  
71
DeviceRef DeviceManagerJack::getDefaultInput()
72
{
73
    return mDevices[0];
74
}
75

  
76
std::string DeviceManagerJack::getName( const DeviceRef &device )
77
{
78
    return device->getKey();
79
}
80

  
81
size_t DeviceManagerJack::getNumInputChannels( const DeviceRef &device )
82
{
83
    if( device->getKey() == mDevices[0]->getKey() )
84
        return 2;
85
    else
86
        return 0;
87
}
88

  
89
size_t DeviceManagerJack::getNumOutputChannels( const DeviceRef &device )
90
{
91
    if( device->getKey() == mDevices[1]->getKey() )
92
        return 2;
93
    else
94
        return 0;
95
}
96

  
97
size_t DeviceManagerJack::getSampleRate( const DeviceRef &device )
98
{
99
    return mSampleRate;
100
}
101

  
102
size_t DeviceManagerJack::getFramesPerBlock( const DeviceRef &device )
103
{
104
    return mBufferSize;
105
}
106

  
107

  
108
void DeviceManagerJack::setSampleRate( const DeviceRef &device, size_t sampleRate )
109
{
110
    throw "setSampleRate not supported";
111
}
112

  
113
void DeviceManagerJack::setFramesPerBlock( const DeviceRef &device, size_t framesPerBlock )
114
{
115
    throw "setFramesPerBlock not supported";
116
}
117

  
118

  
119
//! Returns the hardware's actual frames per block, which might not be a power of two.
120
//        size_t getFramesPerBlockHardware( const DeviceRef &device );
121
//
122

  
123
size_t DeviceManagerJack::getFramesPerBlockHardware( const DeviceRef &device )
124
{
125
    return mBufferSize;
126
}
127

  
128

  
129

  
130

  
131

  
132

  
133
} } } // namespace cinder::audio::linux
JackDevice/DeviceManagerJack.h
1
/*
2
 Copyright (c) 2015, The Cinder Project
3

  
4
 This code is intended to be used with the Cinder C++ library, http://libcinder.org
5

  
6
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
7
 the following conditions are met:
8

  
9
    * Redistributions of source code must retain the above copyright notice, this list of conditions and
10
	the following disclaimer.
11
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
12
	the following disclaimer in the documentation and/or other materials provided with the distribution.
13

  
14
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
15
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
16
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
17
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
18
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21
 POSSIBILITY OF SUCH DAMAGE.
22
*/
23

  
24
#pragma once
25

  
26
#include "cinder/audio/Device.h"
27

  
28
namespace cinder { namespace audio { namespace linux {
29

  
30
class DeviceManagerJack : public DeviceManager {
31
  public:
32

  
33
	DeviceManagerJack();
34
	virtual ~DeviceManagerJack();
35

  
36
	const std::vector<DeviceRef>& getDevices()		override;
37
	DeviceRef getDefaultOutput()				override;
38
	DeviceRef getDefaultInput()				override;
39

  
40
	std::string getName( const DeviceRef &device ) 		override;
41
	size_t getNumInputChannels( const DeviceRef &device )	override;
42
	size_t getNumOutputChannels( const DeviceRef &device )	override;
43
	size_t getSampleRate( const DeviceRef &device )		override;
44
	size_t getFramesPerBlock( const DeviceRef &device )	override;
45

  
46
	void setSampleRate( const DeviceRef &device, size_t sampleRate )		override;
47
	void setFramesPerBlock( const DeviceRef &device, size_t framesPerBlock )	override;
48

  
49
	//! Returns the hardware's actual frames per block, which might not be a power of two.
50
	size_t getFramesPerBlockHardware( const DeviceRef &device );
51

  
52
private:
53

  
54
	std::vector<DeviceRef> mDevices;
55
	DeviceRef   mDefaultOutDevice;
56
	DeviceRef   mDefaultInDevice;
57
    size_t mSampleRate;
58
    size_t mBufferSize;
59
};	
60

  
61
} } } // namespace cinder::audio::linux 	
1
/*
2
 Copyright (c) 2015, The Cinder Project
3

  
4
 This code is intended to be used with the Cinder C++ library, http://libcinder.org
5

  
6
 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
7
 the following conditions are met:
8

  
9
    * Redistributions of source code must retain the above copyright notice, this list of conditions and
10
	the following disclaimer.
11
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
12
	the following disclaimer in the documentation and/or other materials provided with the distribution.
13

  
14
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
15
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
16
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
17
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
18
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
21
 POSSIBILITY OF SUCH DAMAGE.
22
*/
23

  
24
#pragma once
25

  
26
#include "cinder/audio/Device.h"
27

  
28
namespace cinder { namespace audio { namespace linux {
29

  
30
class DeviceManagerJack : public DeviceManager {
31
  public:
32

  
33
	DeviceManagerJack();
34
	virtual ~DeviceManagerJack();
35

  
36
	const std::vector<DeviceRef>& getDevices()		override;
37
	DeviceRef getDefaultOutput()				override;
38
	DeviceRef getDefaultInput()				override;
39

  
40
	std::string getName( const DeviceRef &device ) 		override;
41
	size_t getNumInputChannels( const DeviceRef &device )	override;
42
	size_t getNumOutputChannels( const DeviceRef &device )	override;
43
	size_t getSampleRate( const DeviceRef &device )		override;
44
	size_t getFramesPerBlock( const DeviceRef &device )	override;
45

  
46
	void setSampleRate( const DeviceRef &device, size_t sampleRate )		override;
47
	void setFramesPerBlock( const DeviceRef &device, size_t framesPerBlock )	override;
48

  
49
	//! Returns the hardware's actual frames per block, which might not be a power of two.
50
	size_t getFramesPerBlockHardware( const DeviceRef &device );
51

  
52
private:
53

  
54
	std::vector<DeviceRef> mDevices;
55
	DeviceRef   mDefaultOutDevice;
56
	DeviceRef   mDefaultInDevice;
57
    size_t mSampleRate;
58
    size_t mBufferSize;
59
};	
60

  
61
} } } // namespace cinder::audio::linux 	

Also available in: Unified diff