mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2026-10-08 00:00:23 -04:00
Fix crash selecting devices whose driver reports sample rates as a range
Drivers that only implement getSampleRateRange() (e.g. the usdr module for Wavelet Lab xSDR) crash CubicSDR on device start with: terminating due to uncaught exception of type std::runtime_error: SoapyUSDR::setSampleRate() unable to set samplerate! Two problems in SDRDeviceInfo::getSampleRates(): - SoapySDR's deprecated-API shim expands a continuous rate range into a stepped list whose first entry is 0. The 0 survives decimation, getSampleRateNear() picks it, and the driver throws on setSampleRate(0). Filter out non-positive rates. - If a driver returns an empty rate list, the existing code calls sampleRates.back() on an empty vector (undefined behavior). Synthesize a candidate list from getSampleRateRange() instead, fall back to the range endpoints, and bail out cleanly if there is no rate information at all. Verified on a Wavelet Lab xSDR over USB: device selection previously aborted the app, now starts and streams normally.
This commit is contained in:
@@ -196,6 +196,48 @@ std::vector<long> SDRDeviceInfo::getSampleRates(int direction, size_t channel) {
|
||||
//the original list returned from the driver:
|
||||
std::vector<double> sampleRates = dev->listSampleRates(direction, channel);
|
||||
|
||||
//drop bogus non-positive rates: range-only drivers (e.g. usdr/xsdr) go through
|
||||
//the SoapySDR deprecated-API shim, which can emit a 0 entry that later gets
|
||||
//selected and makes the driver throw on setSampleRate(0).
|
||||
sampleRates.erase(std::remove_if(sampleRates.begin(), sampleRates.end(),
|
||||
[](double r) { return r <= 0; }), sampleRates.end());
|
||||
|
||||
//some drivers (e.g. usdr/xsdr) only report a continuous range and return an
|
||||
//empty discrete list; synthesize candidate rates from the range instead.
|
||||
if (sampleRates.empty()) {
|
||||
|
||||
SoapySDR::RangeList rateRanges = dev->getSampleRateRange(direction, channel);
|
||||
|
||||
const double candidateRates[] = { 250000, 500000, 1000000, 2000000, 2500000,
|
||||
4000000, 5000000, 8000000, 10000000, 16000000, 20000000, 25000000,
|
||||
32000000, 40000000, 50000000, 64000000, 80000000, 100000000, 125000000 };
|
||||
|
||||
for (double candidate : candidateRates) {
|
||||
for (const auto& range : rateRanges) {
|
||||
if (candidate >= range.minimum() && candidate <= range.maximum()) {
|
||||
sampleRates.push_back(candidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//still nothing usable: fall back to the range endpoints themselves
|
||||
if (sampleRates.empty()) {
|
||||
for (const auto& range : rateRanges) {
|
||||
sampleRates.push_back(range.minimum());
|
||||
if (range.maximum() != range.minimum()) {
|
||||
sampleRates.push_back(range.maximum());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//no rate info at all: bail out with an empty list rather than reading
|
||||
//past the end of an empty vector below.
|
||||
if (sampleRates.empty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
//be paranoid, sort by increasing rates...
|
||||
std::sort(sampleRates.begin(), sampleRates.end(), [](double a, double b) -> bool { return a < b; });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user