Esempio n. 1
0
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();
}
Esempio n. 2
0
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;
        }
    }
}