Separate IO
Initial separation of input and output devices. Assisted by our super friend ChatGpt.
This commit is contained in:
+11
-8
@@ -1223,7 +1223,9 @@ namespace pipedal
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
alsa_device_name = jackServerSettings.GetAlsaInputDevice();
|
std::string inputName = jackServerSettings.GetAlsaInputDevice();
|
||||||
|
std::string outputName = jackServerSettings.GetAlsaOutputDevice();
|
||||||
|
|
||||||
|
|
||||||
this->numberOfBuffers = jackServerSettings.GetNumberOfBuffers();
|
this->numberOfBuffers = jackServerSettings.GetNumberOfBuffers();
|
||||||
this->bufferSize = jackServerSettings.GetBufferSize();
|
this->bufferSize = jackServerSettings.GetBufferSize();
|
||||||
@@ -1232,7 +1234,7 @@ namespace pipedal
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
err = snd_pcm_open(&playbackHandle, alsa_device_name.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
err = snd_pcm_open(&playbackHandle, outputName.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
{
|
{
|
||||||
switch (errno)
|
switch (errno)
|
||||||
@@ -1267,7 +1269,7 @@ namespace pipedal
|
|||||||
snd_pcm_nonblock(playbackHandle, 0);
|
snd_pcm_nonblock(playbackHandle, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_open(&captureHandle, alsa_device_name.c_str(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
err = snd_pcm_open(&captureHandle, inputName.c_str(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
{
|
{
|
||||||
@@ -1934,7 +1936,8 @@ namespace pipedal
|
|||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
std::string alsaDeviceName = jackServerSettings.GetAlsaInputDevice();
|
std::string inDev = jackServerSettings.GetAlsaInputDevice();
|
||||||
|
std::string outDev = jackServerSettings.GetAlsaOutputDevice();
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -1942,7 +1945,7 @@ namespace pipedal
|
|||||||
int err;
|
int err;
|
||||||
for (int retry = 0; retry < 2; ++retry)
|
for (int retry = 0; retry < 2; ++retry)
|
||||||
{
|
{
|
||||||
err = snd_pcm_open(&playbackHandle, alsaDeviceName.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
err = snd_pcm_open(&playbackHandle, outDev.c_str(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||||
if (err < 0) // field report of a device that is present, but won't immediately open.
|
if (err < 0) // field report of a device that is present, but won't immediately open.
|
||||||
{
|
{
|
||||||
sleep(1);
|
sleep(1);
|
||||||
@@ -1958,7 +1961,7 @@ namespace pipedal
|
|||||||
|
|
||||||
for (int retry = 0; retry < 15; ++retry)
|
for (int retry = 0; retry < 15; ++retry)
|
||||||
{
|
{
|
||||||
err = snd_pcm_open(&captureHandle, alsaDeviceName.c_str(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
err = snd_pcm_open(&captureHandle, inDev.c_str(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
|
||||||
if (err == -EBUSY)
|
if (err == -EBUSY)
|
||||||
{
|
{
|
||||||
sleep(1);
|
sleep(1);
|
||||||
@@ -1981,8 +1984,8 @@ namespace pipedal
|
|||||||
snd_pcm_hw_params_any(playbackHandle, playbackHwParams);
|
snd_pcm_hw_params_any(playbackHandle, playbackHwParams);
|
||||||
snd_pcm_hw_params_any(captureHandle, captureHwParams);
|
snd_pcm_hw_params_any(captureHandle, captureHwParams);
|
||||||
|
|
||||||
SetPreferredAlsaFormat(alsaDeviceName, "capture", captureHandle, captureHwParams);
|
SetPreferredAlsaFormat(inDev, "capture", captureHandle, captureHwParams);
|
||||||
SetPreferredAlsaFormat(alsaDeviceName, "output", playbackHandle, playbackHwParams);
|
SetPreferredAlsaFormat(outDev, "output", playbackHandle, playbackHwParams);
|
||||||
|
|
||||||
unsigned int sampleRate = jackServerSettings.GetSampleRate();
|
unsigned int sampleRate = jackServerSettings.GetSampleRate();
|
||||||
err = snd_pcm_hw_params_set_rate_near(playbackHandle, playbackHwParams, &sampleRate, 0);
|
err = snd_pcm_hw_params_set_rate_near(playbackHandle, playbackHwParams, &sampleRate, 0);
|
||||||
|
|||||||
@@ -148,7 +148,13 @@ void JackServerSettings::ReadJackDaemonConfiguration()
|
|||||||
this->bufferSize_ = GetJackArg(argv, "-p", "--period");
|
this->bufferSize_ = GetJackArg(argv, "-p", "--period");
|
||||||
this->numberOfBuffers_ = (uint32_t)GetJackArg(argv, "-n", "--nperiods");
|
this->numberOfBuffers_ = (uint32_t)GetJackArg(argv, "-n", "--nperiods");
|
||||||
this->sampleRate_ = (uint32_t)GetJackArg(argv, "-r", "--rate");
|
this->sampleRate_ = (uint32_t)GetJackArg(argv, "-r", "--rate");
|
||||||
this->alsaDevice_ = GetJackStringArg(argv,"-d", "--device");
|
// read new dual device flags, fallback on old -d/--device
|
||||||
|
std::string capDev = GetJackStringArg(argv, "-C", "--capture");
|
||||||
|
std::string playDev = GetJackStringArg(argv, "-P", "--playback");
|
||||||
|
std::string dev = "";
|
||||||
|
try { dev = GetJackStringArg(argv, "-d", "--device"); } catch(...) {}
|
||||||
|
this->alsaInputDevice_ = capDev.empty() ? dev : capDev;
|
||||||
|
this->alsaOutputDevice_ = playDev.empty() ? dev : playDev;
|
||||||
this->valid_ = true;
|
this->valid_ = true;
|
||||||
}
|
}
|
||||||
catch (std::exception &)
|
catch (std::exception &)
|
||||||
@@ -223,7 +229,9 @@ void JackServerSettings::WriteDaemonConfig()
|
|||||||
// Lower to -P70 in order to allow the USB soft-irq to run at higher priority than JACK (it runs at 80).
|
// Lower to -P70 in order to allow the USB soft-irq to run at higher priority than JACK (it runs at 80).
|
||||||
output << "/usr/bin/jackd "
|
output << "/usr/bin/jackd "
|
||||||
<< "-R -P70 --silent"
|
<< "-R -P70 --silent"
|
||||||
<< " -dalsa -d" << this->alsaDevice_
|
<< " -dalsa"
|
||||||
|
<< " -C" << this->GetAlsaInputDevice()
|
||||||
|
<< " -P" << this->GetAlsaOutputDevice()
|
||||||
<< " -r" << this->sampleRate_
|
<< " -r" << this->sampleRate_
|
||||||
<< " -p" << this->bufferSize_
|
<< " -p" << this->bufferSize_
|
||||||
<< " -n" << this->numberOfBuffers_ << " -Xseq"
|
<< " -n" << this->numberOfBuffers_ << " -Xseq"
|
||||||
@@ -246,7 +254,8 @@ JSON_MAP_REFERENCE(JackServerSettings, valid)
|
|||||||
JSON_MAP_REFERENCE(JackServerSettings, isOnboarding)
|
JSON_MAP_REFERENCE(JackServerSettings, isOnboarding)
|
||||||
JSON_MAP_REFERENCE(JackServerSettings, rebootRequired)
|
JSON_MAP_REFERENCE(JackServerSettings, rebootRequired)
|
||||||
JSON_MAP_REFERENCE(JackServerSettings, isJackAudio)
|
JSON_MAP_REFERENCE(JackServerSettings, isJackAudio)
|
||||||
JSON_MAP_REFERENCE(JackServerSettings, alsaDevice)
|
JSON_MAP_REFERENCE(JackServerSettings, alsaInputDevice)
|
||||||
|
JSON_MAP_REFERENCE(JackServerSettings, alsaOutputDevice)
|
||||||
JSON_MAP_REFERENCE(JackServerSettings, sampleRate)
|
JSON_MAP_REFERENCE(JackServerSettings, sampleRate)
|
||||||
JSON_MAP_REFERENCE(JackServerSettings, bufferSize)
|
JSON_MAP_REFERENCE(JackServerSettings, bufferSize)
|
||||||
JSON_MAP_REFERENCE(JackServerSettings, numberOfBuffers)
|
JSON_MAP_REFERENCE(JackServerSettings, numberOfBuffers)
|
||||||
|
|||||||
@@ -31,18 +31,24 @@ namespace pipedal
|
|||||||
bool isOnboarding_ = true;
|
bool isOnboarding_ = true;
|
||||||
bool isJackAudio_ = JACK_HOST ? true : false;
|
bool isJackAudio_ = JACK_HOST ? true : false;
|
||||||
bool rebootRequired_ = false;
|
bool rebootRequired_ = false;
|
||||||
std::string alsaDevice_;
|
std::string alsaInputDevice_;
|
||||||
|
std::string alsaOutputDevice_;
|
||||||
uint64_t sampleRate_ = 0;
|
uint64_t sampleRate_ = 0;
|
||||||
uint32_t bufferSize_ = 64;
|
uint32_t bufferSize_ = 64;
|
||||||
uint32_t numberOfBuffers_ = 3;
|
uint32_t numberOfBuffers_ = 3;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void SetAlsaInputDevice(const std::string &d){ alsaInputDevice_ = d; }
|
||||||
|
void SetAlsaOutputDevice(const std::string &d){ alsaOutputDevice_ = d; }
|
||||||
JackServerSettings();
|
JackServerSettings();
|
||||||
JackServerSettings(
|
JackServerSettings(
|
||||||
const std::string alsaInputDevice,
|
const std::string alsaInputDevice,
|
||||||
uint64_t sampleRate, uint32_t bufferSize, uint32_t numberOfBuffers)
|
uint64_t sampleRate,
|
||||||
|
uint32_t bufferSize,
|
||||||
|
uint32_t numberOfBuffers)
|
||||||
: valid_(true),
|
: valid_(true),
|
||||||
alsaDevice_(alsaInputDevice),
|
alsaInputDevice_(alsaInputDevice),
|
||||||
|
alsaOutputDevice_(alsaInputDevice), // default same
|
||||||
sampleRate_(sampleRate),
|
sampleRate_(sampleRate),
|
||||||
bufferSize_(bufferSize),
|
bufferSize_(bufferSize),
|
||||||
numberOfBuffers_(numberOfBuffers),
|
numberOfBuffers_(numberOfBuffers),
|
||||||
@@ -53,16 +59,17 @@ namespace pipedal
|
|||||||
uint64_t GetSampleRate() const { return sampleRate_; }
|
uint64_t GetSampleRate() const { return sampleRate_; }
|
||||||
uint32_t GetBufferSize() const { return bufferSize_; }
|
uint32_t GetBufferSize() const { return bufferSize_; }
|
||||||
uint32_t GetNumberOfBuffers() const { return numberOfBuffers_; }
|
uint32_t GetNumberOfBuffers() const { return numberOfBuffers_; }
|
||||||
const std::string &GetAlsaInputDevice() const { return alsaDevice_; }
|
const std::string &GetAlsaInputDevice() const { return alsaInputDevice_; }
|
||||||
|
const std::string &GetAlsaOutputDevice() const { return alsaOutputDevice_; }
|
||||||
void UseDummyAudioDevice() {
|
void UseDummyAudioDevice() {
|
||||||
this->valid_ = true;
|
this->valid_ = true;
|
||||||
if (sampleRate_ == 0) sampleRate_ = 48000;
|
if (sampleRate_ == 0) sampleRate_ = 48000;
|
||||||
this->alsaDevice_ = "dummy:channels_2";
|
this->alsaInputDevice_ = "__DUMMY_AUDIO__dummy:channels_2";
|
||||||
|
this->alsaOutputDevice_ = "__DUMMY_AUDIO__dummy:channels_2";
|
||||||
}
|
}
|
||||||
bool IsDummyAudioDevice() const {
|
bool IsDummyAudioDevice() const {
|
||||||
return
|
return this->alsaInputDevice_.starts_with("__DUMMY_AUDIO__")
|
||||||
this->alsaDevice_.starts_with("__DUMMY_AUDIO__")
|
|| this->alsaOutputDevice_.starts_with("__DUMMY_AUDIO__");
|
||||||
|| this->alsaDevice_.starts_with("dummy:");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadJackDaemonConfiguration();
|
void ReadJackDaemonConfiguration();
|
||||||
@@ -89,7 +96,7 @@ namespace pipedal
|
|||||||
|
|
||||||
bool Equals(const JackServerSettings &other)
|
bool Equals(const JackServerSettings &other)
|
||||||
{
|
{
|
||||||
return this->alsaDevice_ == other.alsaDevice_ && this->sampleRate_ == other.sampleRate_ && this->bufferSize_ == other.bufferSize_ && this->numberOfBuffers_ == other.numberOfBuffers_;
|
return this->alsaInputDevice_ == other.alsaInputDevice_ && this->alsaOutputDevice_ == other.alsaOutputDevice_ && this->sampleRate_ == other.sampleRate_ && this->bufferSize_ == other.bufferSize_ && this->numberOfBuffers_ == other.numberOfBuffers_;
|
||||||
}
|
}
|
||||||
|
|
||||||
DECLARE_JSON_MAP(JackServerSettings);
|
DECLARE_JSON_MAP(JackServerSettings);
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export default class JackServerSettings {
|
|||||||
this.isOnboarding = input.isOnboarding;
|
this.isOnboarding = input.isOnboarding;
|
||||||
this.isJackAudio = input.isJackAudio;
|
this.isJackAudio = input.isJackAudio;
|
||||||
this.rebootRequired = input.rebootRequired;
|
this.rebootRequired = input.rebootRequired;
|
||||||
this.alsaDevice = input.alsaDevice?? "";
|
this.alsaInputDevice = input.alsaInputDevice ?? "";
|
||||||
|
this.alsaOutputDevice = input.alsaOutputDevice ?? "";
|
||||||
this.sampleRate = input.sampleRate;
|
this.sampleRate = input.sampleRate;
|
||||||
this.bufferSize = input.bufferSize;
|
this.bufferSize = input.bufferSize;
|
||||||
this.numberOfBuffers = input.numberOfBuffers;
|
this.numberOfBuffers = input.numberOfBuffers;
|
||||||
@@ -48,16 +49,18 @@ export default class JackServerSettings {
|
|||||||
isOnboarding: boolean = true;
|
isOnboarding: boolean = true;
|
||||||
rebootRequired = false;
|
rebootRequired = false;
|
||||||
isJackAudio = false;
|
isJackAudio = false;
|
||||||
alsaDevice: string = "";
|
alsaInputDevice: string = "";
|
||||||
|
alsaOutputDevice: string = "";
|
||||||
sampleRate = 48000;
|
sampleRate = 48000;
|
||||||
bufferSize = 64;
|
bufferSize = 64;
|
||||||
numberOfBuffers = 3;
|
numberOfBuffers = 3;
|
||||||
|
|
||||||
getSummaryText() {
|
getSummaryText() {
|
||||||
if (this.valid) {
|
if (this.valid) {
|
||||||
let device = this.alsaDevice;
|
let inDev = this.alsaInputDevice.startsWith("hw:") ? this.alsaInputDevice .substring(3) : this.alsaInputDevice;
|
||||||
if (device.startsWith("hw:")) device = device.substring(3);
|
let outDev = this.alsaOutputDevice.startsWith("hw:") ? this.alsaOutputDevice.substring(3) : this.alsaOutputDevice;
|
||||||
return device + " - Rate: " + this.sampleRate + " BufferSize: " + this.bufferSize + " Buffers: " + this.numberOfBuffers;
|
return "In: "+inDev+" Out: "+outDev+" — Rate "+this.sampleRate+", "+this.bufferSize+"×"+this.numberOfBuffers;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return "Not configured";
|
return "Not configured";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -282,7 +282,9 @@ const JackServerSettingsDialog = withStyles(
|
|||||||
}
|
}
|
||||||
if (!selectedDevice) {
|
if (!selectedDevice) {
|
||||||
selectedDevice = alsaDevices[0];
|
selectedDevice = alsaDevices[0];
|
||||||
result.alsaDevice = selectedDevice.id;
|
// if nothing selected yet, pick first for both:
|
||||||
|
if (!result.alsaInputDevice ) result.alsaInputDevice = selectedDevice.id;
|
||||||
|
if (!result.alsaOutputDevice) result.alsaOutputDevice = selectedDevice.id;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (result.sampleRate === 0) result.sampleRate = 48000;
|
if (result.sampleRate === 0) result.sampleRate = 48000;
|
||||||
@@ -292,7 +294,7 @@ const JackServerSettingsDialog = withStyles(
|
|||||||
result.bufferSize = bestBuffers.bufferSize;
|
result.bufferSize = bestBuffers.bufferSize;
|
||||||
result.numberOfBuffers = bestBuffers.numberOfBuffers;
|
result.numberOfBuffers = bestBuffers.numberOfBuffers;
|
||||||
|
|
||||||
result.valid = true;
|
result.valid = !!result.alsaInputDevice && !!result.alsaOutputDevice;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +401,25 @@ const JackServerSettingsDialog = withStyles(
|
|||||||
this.props.onApply(this.state.jackServerSettings.clone());
|
this.props.onApply(this.state.jackServerSettings.clone());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
handleInputDeviceChanged(e: any) {
|
||||||
|
const d = e.target.value as string;
|
||||||
|
let s = this.state.jackServerSettings.clone();
|
||||||
|
s.alsaInputDevice = d;
|
||||||
|
this.setState({
|
||||||
|
jackServerSettings: s,
|
||||||
|
okEnabled: isOkEnabled(s, this.state.alsaDevices)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleOutputDeviceChanged(e: any) {
|
||||||
|
const d = e.target.value as string;
|
||||||
|
let s = this.state.jackServerSettings.clone();
|
||||||
|
s.alsaOutputDevice = d;
|
||||||
|
this.setState({
|
||||||
|
jackServerSettings: s,
|
||||||
|
okEnabled: isOkEnabled(s, this.state.alsaDevices)
|
||||||
|
});
|
||||||
|
}
|
||||||
render() {
|
render() {
|
||||||
const classes = withStyles.getClasses(this.props);
|
const classes = withStyles.getClasses(this.props);
|
||||||
|
|
||||||
@@ -433,29 +453,33 @@ const JackServerSettingsDialog = withStyles(
|
|||||||
>
|
>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<div>
|
<div>
|
||||||
|
{/* Audio Input Device */}
|
||||||
<FormControl className={classes.formControl}>
|
<FormControl className={classes.formControl}>
|
||||||
<InputLabel htmlFor="jsd_device">Device</InputLabel>
|
<InputLabel htmlFor="jsd_inputDevice">Input Device</InputLabel>
|
||||||
<Select variant="standard" onChange={(e) => this.handleDeviceChanged(e)}
|
<Select
|
||||||
value={this.state.jackServerSettings.alsaDevice}
|
id="jsd_inputDevice"
|
||||||
|
value={this.state.jackServerSettings.alsaInputDevice}
|
||||||
|
onChange={e => this.handleInputDeviceChanged(e)}
|
||||||
style={{ width: 220 }}
|
style={{ width: 220 }}
|
||||||
inputProps={{
|
|
||||||
name: "Device",
|
|
||||||
id: "jsd_device",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{(noDevices && !waitingForDevices) &&
|
{this.state.alsaDevices!.map(d => (
|
||||||
(
|
<MenuItem key={d.id} value={d.id}>{d.name}</MenuItem>
|
||||||
<MenuItem value={INVALID_DEVICE_ID}>No suitable devices.</MenuItem>
|
))}
|
||||||
)
|
</Select>
|
||||||
}
|
</FormControl>
|
||||||
{((!noDevices) && !waitingForDevices) && (
|
|
||||||
this.state.alsaDevices!.map((device) =>
|
|
||||||
(
|
|
||||||
<MenuItem key={device.id} value={device.id}>{device.name}</MenuItem>
|
|
||||||
)
|
|
||||||
|
|
||||||
)
|
{/* Audio Output Device */}
|
||||||
)}
|
<FormControl className={classes.formControl}>
|
||||||
|
<InputLabel htmlFor="jsd_outputDevice">Output Device</InputLabel>
|
||||||
|
<Select
|
||||||
|
id="jsd_outputDevice"
|
||||||
|
value={this.state.jackServerSettings.alsaOutputDevice}
|
||||||
|
onChange={e => this.handleOutputDeviceChanged(e)}
|
||||||
|
style={{ width: 220 }}
|
||||||
|
>
|
||||||
|
{this.state.alsaDevices!.map(d => (
|
||||||
|
<MenuItem key={d.id} value={d.id}>{d.name}</MenuItem>
|
||||||
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</div><div>
|
</div><div>
|
||||||
|
|||||||
Reference in New Issue
Block a user