bool QAudioOutputPrivate::deviceReady()
{
    if(pullMode) {
        int l = 0;
        int chunks = bytesAvailable/period_size;
        if(chunks==0) {
            bytesAvailable = bytesFree();
            return false;
        }
#ifdef DEBUG_AUDIO
        qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes";
        qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<period_size*chunks;
#endif
        int input = period_frames*chunks;
        if(input > (int)buffer_frames)
            input = buffer_frames;
        l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input));
        if(l > 0) {
            // Got some data to output
            if(deviceState != QAudio::ActiveState)
                return true;
            write(audioBuffer,l);
            bytesAvailable = bytesFree();

        } else if(l == 0) {
            // Did not get any data to output
            bytesAvailable = bytesFree();
            if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
                // Underrun
                errorState = QAudio::UnderrunError;
                deviceState = QAudio::IdleState;
                emit stateChanged(deviceState);
            }

        } else if(l < 0) {
            close();
            errorState = QAudio::IOError;
            emit stateChanged(deviceState);
        }
    } else
        bytesAvailable = bytesFree();

    if(deviceState != QAudio::ActiveState)
        return true;

    if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) {
        emit notify();
        elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime;
        timeStamp.restart();
    }
    return true;
}
Exemplo n.º 2
0
void AudioOutput::write()
{
    int freeBytes = bytesFree();
    if(freeBytes <= 0)
        return;
    /*first, send the remain data of audio buffer*/
    int remain = size;
    //write remain data
    if(remain < freeBytes && remain > 0){
        writeData(remain);
        freeBytes -= remain;
    }
    /*second, convert the avframe to the audio buffer and send to the device*/
    while(freeBytes > 0 && aw->audioFrameQ.size() > 0){
        //convert AVframe data to audio buffer
        std::shared_ptr<Frame> sharedFrame;
        if(!aw->audioFrameQ.pop(sharedFrame))
            return;
        if(sharedFrame->serial != aw->serial)
            continue;
        readAVFrame(sharedFrame->frame);
        if(freeBytes <= size){
            writeData(freeBytes);
            freeBytes = 0;
        } else{
            int len = size;
            writeData(len);
            freeBytes -= len;
        }
    }
}
void QAudioOutputPrivate::updateAvailable()
{
#ifdef DEBUG_AUDIO
    QTime now(QTime::currentTime());
    qDebug()<<now.second()<<"s "<<now.msec()<<"ms :updateAvailable()";
#endif
    bytesAvailable = bytesFree();
}
Exemplo n.º 4
0
void QAudioOutputPrivate::suspend()
{
    if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState) {
        int delay = (buffer_size-bytesFree())*1000/(settings.frequency()
                *settings.channels()*(settings.sampleSize()/8));
        waveOutPause(hWaveOut);
        Sleep(delay+10);
        deviceState = QAudio::SuspendedState;
        errorState = QAudio::NoError;
        emit stateChanged(deviceState);
    }
}
void QAudioOutputPrivate::userFeed()
{
    if(deviceState == QAudio::StoppedState || deviceState == QAudio::SuspendedState)
        return;
#ifdef DEBUG_AUDIO
    QTime now(QTime::currentTime());
    qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() OUT";
#endif
    if(deviceState ==  QAudio::IdleState)
        bytesAvailable = bytesFree();

    deviceReady();
}
Exemplo n.º 6
0
void QAudioOutputPrivate::feedback()
{
#ifdef DEBUG_AUDIO
    QTime now(QTime::currentTime());
    qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback()";
#endif
    bytesAvailable = bytesFree();

    if(!(deviceState==QAudio::StoppedState||deviceState==QAudio::SuspendedState)) {
        if(bytesAvailable >= period_size)
            QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection);
    }
}
Exemplo n.º 7
0
void QAudioOutputPrivate::close()
{
    if(deviceState == QAudio::StoppedState)
        return;

    deviceState = QAudio::StoppedState;
    errorState = QAudio::NoError;
    int delay = (buffer_size-bytesFree())*1000/(settings.frequency()
                  *settings.channels()*(settings.sampleSize()/8));
    waveOutReset(hWaveOut);
    Sleep(delay+10);

    freeBlocks(waveBlocks);
    waveOutClose(hWaveOut);
    delete [] audioBuffer;
    audioBuffer = 0;
    buffer_size = 0;
}
Exemplo n.º 8
0
qint64 QAudioOutputPrivate::write( const char *data, qint64 len )
{
    // Write out some audio data
    if ( !handle )
        return 0;
#ifdef DEBUG_AUDIO
    qDebug()<<"frames to write out = "<<
            snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes";
#endif
    int frames, err;
    int space = bytesFree();
    if(len < space) {
        // Just write it
        frames = snd_pcm_bytes_to_frames( handle, (int)len );
        err = snd_pcm_writei( handle, data, frames );
    } else {
        // Only write space worth
        frames = snd_pcm_bytes_to_frames( handle, (int)space );
        err = snd_pcm_writei( handle, data, frames );
    }
    if(err > 0) {
        totalTimeValue += err;
        resuming = false;
        errorState = QAudio::NoError;
        if (deviceState != QAudio::ActiveState) {
            deviceState = QAudio::ActiveState;
            emit stateChanged(deviceState);
        }
        return snd_pcm_frames_to_bytes( handle, err );
    } else
        err = xrun_recovery(err);

    if(err < 0) {
        close();
        errorState = QAudio::FatalError;
        emit errorChanged(errorState);
        deviceState = QAudio::StoppedState;
        emit stateChanged(deviceState);
    }
    return 0;
}
Exemplo n.º 9
0
void Buffer::writeData(const uint8_t* pData, uint32_t size)
{
    if (size > bytesFree())
    {
        throw std::logic_error("Not enough room in audio buffer to write data");
    }

    if (m_pWritePtr + size >= m_pEnd)
    {
        uint32_t firstSize  = static_cast<uint32_t>(m_pEnd - m_pWritePtr);
        uint32_t secondSize = size - firstSize;

        memcpy(m_pWritePtr, pData, firstSize);
        memcpy(m_pAudioBuffer, pData + firstSize, secondSize);
        m_pWritePtr = m_pAudioBuffer + secondSize;
    }
    else
    {
        memcpy(m_pWritePtr, pData, size);
        m_pWritePtr += size;
    }

    m_Fill += size;
}
bool QAudioOutputPrivate::open()
{
    if(opened)
        return true;

#ifdef DEBUG_AUDIO
    QTime now(QTime::currentTime());
    qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
#endif
    timeStamp.restart();
    elapsedTimeOffset = 0;

    int dir;
    int err=-1;
    int count=0;
    unsigned int freakuency=settings.frequency();

    QString dev = QLatin1String(m_device.constData());
    QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput);
    if(dev.compare(QLatin1String("default")) == 0) {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        dev = QLatin1String(devices.first().constData());
#else
        dev = QLatin1String("hw:0,0");
#endif
    } else {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        dev = QLatin1String(m_device);
#else
        int idx = 0;
        char *name;

        QString shortName = QLatin1String(m_device.mid(m_device.indexOf('=',0)+1).constData());

	while(snd_card_get_name(idx,&name) == 0) {
            if(qstrncmp(shortName.toLocal8Bit().constData(),name,shortName.length()) == 0)
                break;
            idx++;
	}
        dev = QString(QLatin1String("hw:%1,0")).arg(idx);
#endif
    }

    // Step 1: try and open the device
    while((count < 5) && (err < 0)) {
        err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
        if(err < 0)
            count++;
    }
    if (( err < 0)||(handle == 0)) {
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        return false;
    }
    snd_pcm_nonblock( handle, 0 );

    // Step 2: Set the desired HW parameters.
    snd_pcm_hw_params_alloca( &hwparams );

    bool fatal = false;
    QString errMessage;
    unsigned int chunks = 8;

    err = snd_pcm_hw_params_any( handle, hwparams );
    if ( err < 0 ) {
        fatal = true;
        errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_any: err = %1").arg(err);
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_access( handle, hwparams, access );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_access: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = setFormat();
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_format: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_channels: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 );
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
        if ( err < 0 ) {
            fatal = true;
                errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = snd_pcm_hw_params(handle, hwparams);
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params: err = %1").arg(err);
        }
    }
    if( err < 0) {
        qWarning()<<errMessage;
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        return false;
    }
    snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
    buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
    snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
    period_size = snd_pcm_frames_to_bytes(handle,period_frames);
    snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
    snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);

    // Step 3: Set the desired SW parameters.
    snd_pcm_sw_params_t *swparams;
    snd_pcm_sw_params_alloca(&swparams);
    snd_pcm_sw_params_current(handle, swparams);
    snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
    snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
    snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
    snd_pcm_sw_params(handle, swparams);

    // Step 4: Prepare audio
    if(audioBuffer == 0)
        audioBuffer = new char[snd_pcm_frames_to_bytes(handle,buffer_frames)];
    snd_pcm_prepare( handle );
    snd_pcm_start(handle);

    // Step 5: Setup callback and timer fallback
    snd_async_add_pcm_handler(&ahandler, handle, async_callback, this);
    bytesAvailable = bytesFree();

    // Step 6: Start audio processing
    timer->start(period_time/1000);

    clockStamp.restart();
    timeStamp.restart();
    elapsedTimeOffset = 0;
    errorState  = QAudio::NoError;
    totalTimeValue = 0;
    opened = true;

    return true;
}
Exemplo n.º 11
0
bool QAudioOutputPrivate::deviceReady()
{
    if(deviceState == QAudio::StoppedState)
        return false;

    if(pullMode) {
        int chunks = bytesAvailable/period_size;
#ifdef DEBUG_AUDIO
        qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes";
        qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<chunks*period_size;
#endif
        bool startup = false;
        if(totalTimeValue == 0)
	    startup = true;

	bool full=false;
	EnterCriticalSection(&waveOutCriticalSection);
	if(waveFreeBlockCount==0) full = true;
	LeaveCriticalSection(&waveOutCriticalSection);
	if (full){
#ifdef DEBUG_AUDIO
            qDebug() << "Skipping data as unable to write";
#endif
	    if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime ) {
                emit notify();
		elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime;
		timeStamp.restart();
	    }
	    return true;
	}

        if(startup)
	    waveOutPause(hWaveOut);
        int input = period_size*chunks;
        int l = audioSource->read(audioBuffer,input);
        if(l > 0) {
            int out= write(audioBuffer,l);
            if(out > 0) {
                if (deviceState != QAudio::ActiveState) {
                    deviceState = QAudio::ActiveState;
                    emit stateChanged(deviceState);
                }
            }
            if ( out < l) {
                // Didnt write all data
                audioSource->seek(audioSource->pos()-(l-out));
            }
	    if(startup)
	        waveOutRestart(hWaveOut);
        } else if(l == 0) {
            bytesAvailable = bytesFree();

            int check = 0;
            EnterCriticalSection(&waveOutCriticalSection);
            check = waveFreeBlockCount;
            LeaveCriticalSection(&waveOutCriticalSection);
            if(check == buffer_size/period_size) {
                errorState = QAudio::UnderrunError;
                if (deviceState != QAudio::IdleState) {
                    deviceState = QAudio::IdleState;
                    emit stateChanged(deviceState);
                }
            }

        } else if(l < 0) {
            bytesAvailable = bytesFree();
            errorState = QAudio::IOError;
        }
    } else {
        int buffered;
	EnterCriticalSection(&waveOutCriticalSection);
	buffered = waveFreeBlockCount;
	LeaveCriticalSection(&waveOutCriticalSection);
        errorState = QAudio::UnderrunError;
        if (buffered >= buffer_size/period_size && deviceState == QAudio::ActiveState) {
            deviceState = QAudio::IdleState;
            emit stateChanged(deviceState);
        }
    }
    if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
        return true;

    if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) {
        emit notify();
	elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime;
        timeStamp.restart();
    }

    return true;
}