Esempio n. 1
0
bool AudioDevOSS::init(const QString &device, const AkAudioCaps &caps)
{
    QMutexLocker mutexLockeer(&this->m_mutex);

    this->m_deviceFile.setFileName(QString(device)
                                   .remove(QRegExp(":Input$|:Output$")));

    if (!this->m_deviceFile.open(device.endsWith(":Input")?
                                 QIODevice::ReadOnly: QIODevice::WriteOnly))
        return false;

    int format;
    format = sampleFormats->value(caps.format(), AFMT_QUERY);

    if (ioctl(this->m_deviceFile.handle(), SNDCTL_DSP_SETFMT, &format) < 0)
        goto init_fail;

    int stereo;
    stereo = caps.channels() > 1? 1: 0;

    if (ioctl(this->m_deviceFile.handle(), SNDCTL_DSP_STEREO, &stereo) < 0)
        goto init_fail;

    int sampleRate;
    sampleRate = caps.rate();

    if (ioctl(this->m_deviceFile.handle(), SNDCTL_DSP_SPEED, &sampleRate) < 0)
        goto init_fail;

    if (device.endsWith(":Output")) {
        int fragment = this->m_fragmentSizeMap.value(device);
        ioctl(this->m_deviceFile.handle(), SNDCTL_DSP_SETFRAGMENT, &fragment);
    }

    this->m_curCaps = caps;

    return true;

init_fail:
    this->m_deviceFile.close();

    return false;
}
Esempio n. 2
0
void AudioDeviceElement::setDevice(const QString &device)
{
    if (this->m_device == device)
        return;

    this->m_device = device;
    emit this->deviceChanged(device);

    this->m_mutexLib.lock();
    auto preferredFormat = this->m_audioDevice->preferredFormat(device);
    this->m_mutexLib.unlock();

    AkAudioCaps audioCaps = device == DUMMY_OUTPUT_DEVICE?
                                AkAudioCaps("audio/x-raw,"
                                            "format=s16,"
                                            "bps=2,"
                                            "channels=2,"
                                            "rate=44100,"
                                            "layout=stereo,"
                                            "align=false"):
                                preferredFormat;

    this->setCaps(audioCaps.toCaps());
}
Esempio n. 3
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. 4
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;
        }
    }
}
Esempio n. 5
0
bool AudioDevJack::init(const QString &device, const AkAudioCaps &caps)
{
    if (!this->m_caps.contains(device)
        || caps.channels() < 1
        || caps.channels() > 2
        || caps.rate() != int(jack_get_sample_rate(this->m_client))
        || caps.format() != AkAudioCaps::SampleFormat_flt)
        return false;

    this->m_appPorts.clear();
    this->m_curChannels = 0;
    this->m_curSampleRate = 0;
    this->m_buffer.clear();

    QString portName = device == ":jackinput:"?
                           "input": "output";
    JackPortFlags portFlags = device == ":jackinput:"?
                                  JackPortIsInput: JackPortIsOutput;

    // Create ports for sending/receiving data
    for (int channel = 0; channel < caps.channels(); channel++) {
        auto port = jack_port_register(this->m_client,
                                       QString("%1_%2")
                                           .arg(portName)
                                           .arg(channel + 1).toStdString().c_str(),
                                       JACK_DEFAULT_AUDIO_TYPE,
                                       portFlags,
                                       0);

        if (port)
            this->m_appPorts << port;
    }

    if (this->m_appPorts.size() < caps.channels()) {
        this->m_error = "AudioDevJack::init: No more JACK ports available";
        Q_EMIT this->errorChanged(this->m_error);
        this->uninit();

        return false;
    }

    auto bufferSize = jack_get_buffer_size(this->m_client);

    // Activate JACK client

    if (auto error = jack_status_t(jack_activate(this->m_client))) {
        this->m_error = jackErrorCodes->value(error);
        Q_EMIT this->errorChanged(this->m_error);
        this->uninit();

        return false;
    }

    if (caps.channels() == 1) {
        if (device == ":jackinput:") {
            for (auto port: this->m_devicePorts[device])
                jack_connect(this->m_client,
                             port.toStdString().c_str(),
                             jack_port_name(this->m_appPorts.first()));
        } else {
            for (auto port: this->m_devicePorts[device])
                jack_connect(this->m_client,
                             jack_port_name(this->m_appPorts.first()),
                             port.toStdString().c_str());
        }
    } else {
        auto ports = this->m_devicePorts[device];

        if (device == ":jackinput:") {
            for (int i = 0; i < this->m_appPorts.size(); i++)
                jack_connect(this->m_client,
                             ports[i].toStdString().c_str(),
                             jack_port_name(this->m_appPorts[i]));
        } else {
            for (int i = 0; i < this->m_appPorts.size(); i++)
                jack_connect(this->m_client,
                             jack_port_name(this->m_appPorts[i]),
                             ports[i].toStdString().c_str());
        }
    }

    this->m_curDevice = device;
    this->m_curChannels = caps.channels();
    this->m_curSampleRate = caps.rate();
    this->m_maxBufferSize = int(2
                                * sizeof(jack_default_audio_sample_t)
                                * uint(caps.channels())
                                * bufferSize);
    this->m_isInput = device == ":jackinput:";

    return true;
}