308 lines
7.0 KiB
C++
308 lines
7.0 KiB
C++
/*
|
|
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 <stdio.h>
|
|
#include <assert.h>
|
|
|
|
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
|