1 /*
2 Copyright (C) 2001-2003 Paul Davis
3 Copyright (C) 2004-2008 Grame
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14 
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 
19 */
20 
21 #include "JackPort.h"
22 #include "JackError.h"
23 #include "JackPortType.h"
24 #include <stdio.h>
25 #include <assert.h>
26 
27 namespace Jack
28 {
29 
JackPort()30 JackPort::JackPort()
31 {
32     Release();
33 }
34 
Allocate(int refnum,const char * port_name,const char * port_type,JackPortFlags flags)35 bool JackPort::Allocate(int refnum, const char* port_name, const char* port_type, JackPortFlags flags)
36 {
37     jack_port_type_id_t id = GetPortTypeId(port_type);
38     assert(id >= 0 && id <= PORT_TYPES_MAX);
39     if (id == PORT_TYPES_MAX) {
40         return false;
41     }
42     fTypeId = id;
43     fFlags = flags;
44     fRefNum = refnum;
45     strcpy(fName, port_name);
46     fInUse = true;
47     fLatency = 0;
48     fTotalLatency = 0;
49     fMonitorRequests = 0;
50     fPlaybackLatency.min = fPlaybackLatency.max = 0;
51     fCaptureLatency.min = fCaptureLatency.max = 0;
52     fTied = NO_PORT;
53     fAlias1[0] = '\0';
54     fAlias2[0] = '\0';
55     // DB: At this point we do not know current buffer size in frames,
56     // but every time buffer will be returned to any user,
57     // it will be called with either ClearBuffer or MixBuffers
58     // with correct current buffer size.
59     // So it is safe to init with 0 here.
60     ClearBuffer(0);
61     return true;
62 }
63 
Release()64 void JackPort::Release()
65 {
66     fTypeId = 0;
67     fFlags = JackPortIsInput;
68     fRefNum = -1;
69     fInUse = false;
70     fLatency = 0;
71     fTotalLatency = 0;
72     fMonitorRequests = 0;
73     fPlaybackLatency.min = fPlaybackLatency.max = 0;
74     fCaptureLatency.min = fCaptureLatency.max = 0;
75     fTied = NO_PORT;
76     fAlias1[0] = '\0';
77     fAlias2[0] = '\0';
78 }
79 
GetRefNum() const80 int JackPort::GetRefNum() const
81 {
82     return fRefNum;
83 }
84 
GetLatency() const85 jack_nframes_t JackPort::GetLatency() const
86 {
87     return fLatency;
88 }
89 
GetTotalLatency() const90 jack_nframes_t JackPort::GetTotalLatency() const
91 {
92     return fTotalLatency;
93 }
94 
SetLatency(jack_nframes_t nframes)95 void JackPort::SetLatency(jack_nframes_t nframes)
96 {
97     fLatency = nframes;
98 
99     /* setup the new latency values here,
100 	 * so we don't need to change the backend codes.
101 	 */
102 	if (fFlags & JackPortIsOutput) {
103 		fCaptureLatency.min = nframes;
104 		fCaptureLatency.max = nframes;
105 	}
106 	if (fFlags & JackPortIsInput) {
107 		fPlaybackLatency.min = nframes;
108 		fPlaybackLatency.max = nframes;
109 	}
110 }
111 
SetLatencyRange(jack_latency_callback_mode_t mode,jack_latency_range_t * range)112 void JackPort::SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range)
113 {
114     if (mode == JackCaptureLatency) {
115 		fCaptureLatency = *range;
116 
117 		/* hack to set latency up for
118 		 * backend ports
119 		 */
120 		if ((fFlags & JackPortIsOutput) && (fFlags & JackPortIsPhysical)) {
121 			fLatency = (range->min + range->max) / 2;
122         }
123 	} else {
124         fPlaybackLatency = *range;
125 
126 		/* hack to set latency up for
127 		 * backend ports
128 		 */
129 		if ((fFlags & JackPortIsInput) && (fFlags & JackPortIsPhysical)) {
130 			fLatency = (range->min + range->max) / 2;
131         }
132 	}
133 }
134 
GetLatencyRange(jack_latency_callback_mode_t mode,jack_latency_range_t * range) const135 void JackPort::GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const
136 {
137     if (mode == JackCaptureLatency) {
138 		*range = fCaptureLatency;
139 	} else {
140 		*range = fPlaybackLatency;
141     }
142 }
143 
Tie(jack_port_id_t port_index)144 int JackPort::Tie(jack_port_id_t port_index)
145 {
146     fTied = port_index;
147     return 0;
148 }
149 
UnTie()150 int JackPort::UnTie()
151 {
152     fTied = NO_PORT;
153     return 0;
154 }
155 
RequestMonitor(bool onoff)156 int JackPort::RequestMonitor(bool onoff)
157 {
158     /**
159     jackd.h
160     * If @ref JackPortCanMonitor is set for this @a port, turn input
161     * monitoring on or off. Otherwise, do nothing.
162 
163     if (!(fFlags & JackPortCanMonitor))
164     	return -1;
165     */
166 
167     if (onoff) {
168         fMonitorRequests++;
169     } else if (fMonitorRequests) {
170         fMonitorRequests--;
171     }
172 
173     return 0;
174 }
175 
EnsureMonitor(bool onoff)176 int JackPort::EnsureMonitor(bool onoff)
177 {
178     /**
179     jackd.h
180     * If @ref JackPortCanMonitor is set for this @a port, turn input
181     * monitoring on or off. Otherwise, do nothing.
182 
183     if (!(fFlags & JackPortCanMonitor))
184     	return -1;
185     */
186 
187     if (onoff) {
188         if (fMonitorRequests == 0) {
189             fMonitorRequests++;
190         }
191     } else {
192         if (fMonitorRequests > 0) {
193             fMonitorRequests = 0;
194         }
195     }
196 
197     return 0;
198 }
199 
GetName() const200 const char* JackPort::GetName() const
201 {
202     return fName;
203 }
204 
GetShortName() const205 const char* JackPort::GetShortName() const
206 {
207     /* we know there is always a colon, because we put
208        it there ...
209     */
210     return strchr(fName, ':') + 1;
211 }
212 
GetFlags() const213 int JackPort::GetFlags() const
214 {
215     return fFlags;
216 }
217 
GetType() const218 const char* JackPort::GetType() const
219 {
220     const JackPortType* type = GetPortType(fTypeId);
221     return type->fName;
222 }
223 
SetName(const char * new_name)224 void JackPort::SetName(const char* new_name)
225 {
226     char* colon = strchr(fName, ':');
227     int len = sizeof(fName) - ((int) (colon - fName)) - 2;
228     snprintf(colon + 1, len, "%s", new_name);
229 }
230 
NameEquals(const char * target)231 bool JackPort::NameEquals(const char* target)
232 {
233     char buf[REAL_JACK_PORT_NAME_SIZE+1];
234 
235     /* this nasty, nasty kludge is here because between 0.109.0 and 0.109.1,
236        the ALSA audio backend had the name "ALSA", whereas as before and
237        after it, it was called "alsa_pcm". this stops breakage for
238        any setups that have saved "alsa_pcm" or "ALSA" in their connection
239        state.
240     */
241 
242     if (strncmp(target, "ALSA:capture", 12) == 0 || strncmp(target, "ALSA:playback", 13) == 0) {
243         snprintf(buf, sizeof(buf), "alsa_pcm%s", target + 4);
244         target = buf;
245     }
246 
247     return (strcmp(fName, target) == 0
248             || strcmp(fAlias1, target) == 0
249             || strcmp(fAlias2, target) == 0);
250 }
251 
GetAliases(char * const aliases[2])252 int JackPort::GetAliases(char* const aliases[2])
253 {
254     int cnt = 0;
255 
256     if (fAlias1[0] != '\0') {
257         strncpy(aliases[0], fAlias1, REAL_JACK_PORT_NAME_SIZE);
258         cnt++;
259     }
260 
261     if (fAlias2[0] != '\0') {
262         strncpy(aliases[1], fAlias2, REAL_JACK_PORT_NAME_SIZE);
263         cnt++;
264     }
265 
266     return cnt;
267 }
268 
SetAlias(const char * alias)269 int JackPort::SetAlias(const char* alias)
270 {
271     if (fAlias1[0] == '\0') {
272         strncpy(fAlias1, alias, sizeof(fAlias1));
273     } else if (fAlias2[0] == '\0') {
274         strncpy(fAlias2, alias, sizeof(fAlias2));
275     } else {
276         return -1;
277     }
278 
279     return 0;
280 }
281 
UnsetAlias(const char * alias)282 int JackPort::UnsetAlias(const char* alias)
283 {
284     if (strcmp(fAlias1, alias) == 0) {
285         fAlias1[0] = '\0';
286     } else if (strcmp(fAlias2, alias) == 0) {
287         fAlias2[0] = '\0';
288     } else {
289         return -1;
290     }
291 
292     return 0;
293 }
294 
ClearBuffer(jack_nframes_t frames)295 void JackPort::ClearBuffer(jack_nframes_t frames)
296 {
297     const JackPortType* type = GetPortType(fTypeId);
298     (type->init)(GetBuffer(), frames * sizeof(jack_default_audio_sample_t), frames);
299 }
300 
MixBuffers(void ** src_buffers,int src_count,jack_nframes_t buffer_size)301 void JackPort::MixBuffers(void** src_buffers, int src_count, jack_nframes_t buffer_size)
302 {
303     const JackPortType* type = GetPortType(fTypeId);
304     (type->mixdown)(GetBuffer(), src_buffers, src_count, buffer_size);
305 }
306 
307 } // end of namespace
308