/* Copyright (C) 2001-2003 Paul Davis Copyright (C) 2004-2008 Grame This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "JackPort.h" #include "JackError.h" #include "JackPortType.h" #include #include namespace Jack { JackPort::JackPort() { Release(); } bool JackPort::Allocate(int refnum, const char* port_name, const char* port_type, JackPortFlags flags) { jack_port_type_id_t id = GetPortTypeId(port_type); assert(id >= 0 && id <= PORT_TYPES_MAX); if (id == PORT_TYPES_MAX) { return false; } fTypeId = id; fFlags = flags; fRefNum = refnum; strcpy(fName, port_name); fInUse = true; fLatency = 0; fTotalLatency = 0; fMonitorRequests = 0; fPlaybackLatency.min = fPlaybackLatency.max = 0; fCaptureLatency.min = fCaptureLatency.max = 0; fTied = NO_PORT; fAlias1[0] = '\0'; fAlias2[0] = '\0'; // DB: At this point we do not know current buffer size in frames, // but every time buffer will be returned to any user, // it will be called with either ClearBuffer or MixBuffers // with correct current buffer size. // So it is safe to init with 0 here. ClearBuffer(0); return true; } void JackPort::Release() { fTypeId = 0; fFlags = JackPortIsInput; fRefNum = -1; fInUse = false; fLatency = 0; fTotalLatency = 0; fMonitorRequests = 0; fPlaybackLatency.min = fPlaybackLatency.max = 0; fCaptureLatency.min = fCaptureLatency.max = 0; fTied = NO_PORT; fAlias1[0] = '\0'; fAlias2[0] = '\0'; } int JackPort::GetRefNum() const { return fRefNum; } jack_nframes_t JackPort::GetLatency() const { return fLatency; } jack_nframes_t JackPort::GetTotalLatency() const { return fTotalLatency; } void JackPort::SetLatency(jack_nframes_t nframes) { fLatency = nframes; /* setup the new latency values here, * so we don't need to change the backend codes. */ if (fFlags & JackPortIsOutput) { fCaptureLatency.min = nframes; fCaptureLatency.max = nframes; } if (fFlags & JackPortIsInput) { fPlaybackLatency.min = nframes; fPlaybackLatency.max = nframes; } } void JackPort::SetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) { if (mode == JackCaptureLatency) { fCaptureLatency = *range; /* hack to set latency up for * backend ports */ if ((fFlags & JackPortIsOutput) && (fFlags & JackPortIsPhysical)) { fLatency = (range->min + range->max) / 2; } } else { fPlaybackLatency = *range; /* hack to set latency up for * backend ports */ if ((fFlags & JackPortIsInput) && (fFlags & JackPortIsPhysical)) { fLatency = (range->min + range->max) / 2; } } } void JackPort::GetLatencyRange(jack_latency_callback_mode_t mode, jack_latency_range_t* range) const { if (mode == JackCaptureLatency) { *range = fCaptureLatency; } else { *range = fPlaybackLatency; } } int JackPort::Tie(jack_port_id_t port_index) { fTied = port_index; return 0; } int JackPort::UnTie() { fTied = NO_PORT; return 0; } int JackPort::RequestMonitor(bool onoff) { /** jackd.h * If @ref JackPortCanMonitor is set for this @a port, turn input * monitoring on or off. Otherwise, do nothing. if (!(fFlags & JackPortCanMonitor)) return -1; */ if (onoff) { fMonitorRequests++; } else if (fMonitorRequests) { fMonitorRequests--; } return 0; } int JackPort::EnsureMonitor(bool onoff) { /** jackd.h * If @ref JackPortCanMonitor is set for this @a port, turn input * monitoring on or off. Otherwise, do nothing. if (!(fFlags & JackPortCanMonitor)) return -1; */ if (onoff) { if (fMonitorRequests == 0) { fMonitorRequests++; } } else { if (fMonitorRequests > 0) { fMonitorRequests = 0; } } return 0; } const char* JackPort::GetName() const { return fName; } const char* JackPort::GetShortName() const { /* we know there is always a colon, because we put it there ... */ return strchr(fName, ':') + 1; } int JackPort::GetFlags() const { return fFlags; } const char* JackPort::GetType() const { const JackPortType* type = GetPortType(fTypeId); return type->fName; } void JackPort::SetName(const char* new_name) { char* colon = strchr(fName, ':'); int len = sizeof(fName) - ((int) (colon - fName)) - 2; snprintf(colon + 1, len, "%s", new_name); } bool JackPort::NameEquals(const char* target) { char buf[REAL_JACK_PORT_NAME_SIZE+1]; /* this nasty, nasty kludge is here because between 0.109.0 and 0.109.1, the ALSA audio backend had the name "ALSA", whereas as before and after it, it was called "alsa_pcm". this stops breakage for any setups that have saved "alsa_pcm" or "ALSA" in their connection state. */ if (strncmp(target, "ALSA:capture", 12) == 0 || strncmp(target, "ALSA:playback", 13) == 0) { snprintf(buf, sizeof(buf), "alsa_pcm%s", target + 4); target = buf; } return (strcmp(fName, target) == 0 || strcmp(fAlias1, target) == 0 || strcmp(fAlias2, target) == 0); } int JackPort::GetAliases(char* const aliases[2]) { int cnt = 0; if (fAlias1[0] != '\0') { strncpy(aliases[0], fAlias1, REAL_JACK_PORT_NAME_SIZE); cnt++; } if (fAlias2[0] != '\0') { strncpy(aliases[1], fAlias2, REAL_JACK_PORT_NAME_SIZE); cnt++; } return cnt; } int JackPort::SetAlias(const char* alias) { if (fAlias1[0] == '\0') { strncpy(fAlias1, alias, sizeof(fAlias1)); } else if (fAlias2[0] == '\0') { strncpy(fAlias2, alias, sizeof(fAlias2)); } else { return -1; } return 0; } int JackPort::UnsetAlias(const char* alias) { if (strcmp(fAlias1, alias) == 0) { fAlias1[0] = '\0'; } else if (strcmp(fAlias2, alias) == 0) { fAlias2[0] = '\0'; } else { return -1; } return 0; } void JackPort::ClearBuffer(jack_nframes_t frames) { const JackPortType* type = GetPortType(fTypeId); (type->init)(GetBuffer(), frames * sizeof(jack_default_audio_sample_t), frames); } void JackPort::MixBuffers(void** src_buffers, int src_count, jack_nframes_t buffer_size) { const JackPortType* type = GetPortType(fTypeId); (type->mixdown)(GetBuffer(), src_buffers, src_count, buffer_size); } } // end of namespace