AkAudioCaps AudioDevOSS::deviceCaps(const QString &device, int *fragmentSize) const { QFile pcmFile(QString(device) .remove(QRegExp(":Input$|:Output$"))); if (!pcmFile.open(device.endsWith(":Input")? QIODevice::ReadOnly: QIODevice::WriteOnly)) return AkAudioCaps(); int formats = AFMT_QUERY; if (ioctl(pcmFile.handle(), SNDCTL_DSP_GETFMTS, &formats) < 0) goto deviceCaps_fail; static const QVector<int> preferredFormats = { AFMT_S16_NE, AFMT_S16_LE, AFMT_S16_BE, AFMT_U16_LE, AFMT_U16_BE, AFMT_S8, AFMT_U8 }; int format; format = AFMT_QUERY; for (const auto &fmt: preferredFormats) if (formats & fmt) { format = fmt; break; } if (format == AFMT_QUERY) goto deviceCaps_fail; if (ioctl(pcmFile.handle(), SNDCTL_DSP_SETFMT, &format) < 0) goto deviceCaps_fail; int stereo; stereo = 1; if (ioctl(pcmFile.handle(), SNDCTL_DSP_STEREO, &stereo) < 0) goto deviceCaps_fail; static const QVector<int> preferredSampleRates { 48000, 44100, 22050, 11025, 8000 }; int sampleRate; sampleRate = 0; for (int rate: preferredSampleRates) if (ioctl(pcmFile.handle(), SNDCTL_DSP_SPEED, &rate) >= 0){ sampleRate = rate; break; } if (sampleRate < 1) goto deviceCaps_fail; int channels; channels = stereo? 2: 1; AkAudioCaps::SampleFormat sampleFormat; sampleFormat = sampleFormats->key(format, AkAudioCaps::SampleFormat_none); if (fragmentSize && device.endsWith(":Output")) { // Set the buffer to a maximum of 1024 samples. int bufferSize; bufferSize = BUFFER_SIZE * channels * AkAudioCaps::bitsPerSample(sampleFormat) / 8; // Let's try setting the fragmet to just 2 pieces, and the half of the // buffer size, for low latency. int fragment; fragment = (2 << 16) | (bufferSize / 2); ioctl(pcmFile.handle(), SNDCTL_DSP_SETFRAGMENT, &fragment); // Let's see what OSS did actually set, audio_buf_info info; ioctl(pcmFile.handle(), SNDCTL_DSP_GETOSPACE, &info); *fragmentSize = info.fragsize > 0? ((bufferSize / info.fragsize) << 16) | info.fragsize: 0; } pcmFile.close(); { AkAudioCaps audioCaps; audioCaps.isValid() = true; audioCaps.format() = sampleFormat; audioCaps.bps() = AkAudioCaps::bitsPerSample(audioCaps.format()); audioCaps.channels() = channels; audioCaps.rate() = int(sampleRate); audioCaps.layout() = AkAudioCaps::defaultChannelLayout(audioCaps.channels()); audioCaps.align() = false; return audioCaps; } deviceCaps_fail: pcmFile.close(); return AkAudioCaps(); }
AudioDevJack::AudioDevJack(QObject *parent): AudioDev(parent) { this->m_curChannels = 0; this->m_curSampleRate = 0; this->m_maxBufferSize = 0; this->m_isInput = false; this->m_client = NULL; this->m_descriptions = { {":jackinput:" , "JACK Audio Connection Kit Input" }, {":jackoutput:", "JACK Audio Connection Kit Output"}, }; auto appName = QCoreApplication::applicationName() + QString("_%1").arg(Ak::id()); int maxNameSize = jack_client_name_size() - 1; if (appName.size() > maxNameSize) appName = appName.mid(0, maxNameSize); jack_status_t status; this->m_client = jack_client_open(appName.toStdString().c_str(), JackNullOption, &status); if (!this->m_client) { this->m_error = jackErrorCodes->value(status); Q_EMIT this->errorChanged(this->m_error); return; } // Setup callbacks jack_set_process_callback(this->m_client, AudioDevJack::onProcessCallback, this); jack_on_shutdown(this->m_client, AudioDevJack::onShutdownCallback, this); AkAudioCaps audioCaps; audioCaps.isValid() = true; audioCaps.format() = AkAudioCaps::SampleFormat_flt; audioCaps.bps() = AkAudioCaps::bitsPerSample(audioCaps.format()); audioCaps.rate() = int(jack_get_sample_rate(this->m_client)); audioCaps.layout() = AkAudioCaps::defaultChannelLayout(audioCaps.channels()); audioCaps.align() = false; QMap<QString, JackPortFlags> portTypeMap = { {":jackinput:" , JackPortIsOutput}, {":jackoutput:", JackPortIsInput } }; // Query the number orr channels for (auto deviceId: portTypeMap.keys()) { auto ports = jack_get_ports(this->m_client, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortIsPhysical | portTypeMap[deviceId]); int channels = 0; for (auto portName = ports; portName && *portName; portName++, channels++) this->m_devicePorts[deviceId] << *portName; if (ports) jack_free(ports); if (channels > 0) { audioCaps.channels() = channels; this->m_caps[deviceId] = audioCaps; } } }