예제 #1
0
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 = 0;
    int count=0;
    unsigned int freakuency=settings.frequency();

    if (!settings.isValid()) {
        qWarning("QAudioOutput: open error, invalid format.");
    } else if (settings.sampleRate() <= 0) {
        qWarning("QAudioOutput: open error, invalid sample rate (%d).",
                 settings.sampleRate());
    } else {
        err = -1;
    }

    if (err == 0) {
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        emit errorChanged(errorState);
        return false;
    }

    QString dev = QString(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)
        if (devices.size() > 0)
            dev = QLatin1String(devices.first());
        else
            return false;
#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;
        emit errorChanged(errorState);
        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 ) {
        unsigned int maxBufferTime = 0;
        unsigned int minBufferTime = 0;
        unsigned int maxPeriodTime = 0;
        unsigned int minPeriodTime = 0;

        err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &maxBufferTime, &dir);
        if ( err >= 0)
            err = snd_pcm_hw_params_get_buffer_time_min(hwparams, &minBufferTime, &dir);
        if ( err >= 0)
            err = snd_pcm_hw_params_get_period_time_max(hwparams, &maxPeriodTime, &dir);
        if ( err >= 0)
            err = snd_pcm_hw_params_get_period_time_min(hwparams, &minPeriodTime, &dir);

        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioOutput: buffer/period min and max: err = %1").arg(err);
        } else {
            if (maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time) {
#ifdef DEBUG_AUDIO
                qDebug()<<"defaults out of range";
                qDebug()<<"pmin="<<minPeriodTime<<", pmax="<<maxPeriodTime<<", bmin="<<minBufferTime<<", bmax="<<maxBufferTime;
#endif
                period_time = minPeriodTime;
                if (period_time*4 <= maxBufferTime) {
                    // Use 4 periods if possible
                    buffer_time = period_time*4;
                    chunks = 4;
                } else if (period_time*2 <= maxBufferTime) {
                    // Use 2 periods if possible
                    buffer_time = period_time*2;
                    chunks = 2;
                } else {
                    qWarning()<<"QAudioOutput: alsa only supports single period!";
                    fatal = true;
                }
#ifdef DEBUG_AUDIO
                qDebug()<<"used: buffer_time="<<buffer_time<<", period_time="<<period_time;
#endif
            }
        }
    }
    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;
        emit errorChanged(errorState);
        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;
}
예제 #2
0
TErrors SalsaStream::connect( llaOutputStream* output, llaAudioPipe& buffer) {



	TErrors ret = _open(SND_PCM_NONBLOCK);
	// Update pcm settings
	if( ret != E_OK || (ret = updateSettings(buffer)) != E_OK ) return ret;

	if( (ret = output->open()) != E_OK ) {
		close();
		return ret;
	}

	int err = 0;

	snd_pcm_uframes_t avail_min = 0;
	if(buffer.getBufferLength() < period_size_) {
		close();
		output->close();
		LOGGER().error(E_STREAM_CONFIG, "Buffer length must be higher");
		return E_STREAM_CONFIG;
	}
	else if(buffer.getBufferLength() / period_size_ < 3 ) avail_min = period_size_;
	else avail_min = ((buffer.getBufferLength()/period_size_)-2)*period_size_;



	// Set up the input stream for polling /////////////////////////////////////
	// This is the same process as for the output.

	err = snd_pcm_sw_params_malloc(&sw_config_);
	err = snd_pcm_sw_params_current(pcm_, sw_config_);
	CHECK_SNDERROR(err, E_STREAM_CONFIG);

//	err = snd_pcm_sw_params_set_start_threshold (pcm_, sw_config_, 0U );
//	CHECK_SNDERROR(err, E_STREAM_CONFIG);

	err = snd_pcm_sw_params_set_avail_min(pcm_, sw_config_, avail_min  );
	CHECK_SNDERROR(err, E_STREAM_CONFIG);

	err = snd_pcm_sw_params(pcm_, sw_config_);
	CHECK_SNDERROR(err, E_STREAM_CONFIG);

	snd_pcm_prepare(pcm_);

	snd_pcm_uframes_t frames;

	char *iraw, **niraw;

	while(!buffer.stop() && !buffer.fail()) {
		snd_pcm_start(pcm_);
		if ((err = snd_pcm_wait (pcm_, -1)) < 0) {
			if (err == -EPIPE) {
			  /* EPIPE means xrun */
			  snd_pcm_prepare(pcm_);
			} else if (err < 0) {
				LOGGER().error(E_READ_STREAM, snd_strerror(err));
				snd_pcm_sw_params_free(sw_config_);
				close();
				output->close();
				return E_READ_STREAM;
			}
		}

		frames = snd_pcm_avail_update(pcm_);
		if(frames < 0) {
			LOGGER().error(E_READ_STREAM, snd_strerror(err));
			snd_pcm_sw_params_free(sw_config_);
			close();
			output->close();
			return E_READ_STREAM;
		}

		if(frames > buffer.getBufferLength()) frames = buffer.getBufferLength();

		int rc;
		getRawInputBuffers( buffer, &iraw, &niraw);

		// read from the stream
		if(organization_ == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
			rc = snd_pcm_readn(pcm_, (void**)niraw, frames);
		}
		else {
			rc = snd_pcm_readi(pcm_, (void*)iraw, frames);
		}

		// save the number of frames read
		TSize lastwrite = ((TSize)rc <= buffer.getBufferLength())?
				rc : buffer.getBufferLength();

		setBufferLastWrite(buffer, lastwrite);

		// detect errors
		if (rc == -EPIPE) {
		  /* EPIPE means underrun */
		  snd_pcm_prepare(pcm_);
		} else if (rc < 0) {
			LOGGER().warning(E_READ_STREAM, snd_strerror(rc));
			snd_pcm_sw_params_free(sw_config_);
			close();
			output->close();
			return E_READ_STREAM;
		}

		TErrors reterr;
		if( (reterr=output->write(buffer)) != E_OK ) {
			snd_pcm_sw_params_free(sw_config_);
			close();
			output->close();
		}

	}

	snd_pcm_sw_params_free(sw_config_);
	close();
	output->close();

	return E_OK;
}
예제 #3
0
bool QAudioInputPrivate::open( QObject *input )
{
    // Open the Alsa capture device.
    bool    rc = true;
    int     err;

    unsigned int        freakuency = frequency;

    if ((err = snd_pcm_open(&handle,
                             m_device.constData(), //"plughw:0,0"
                             SND_PCM_STREAM_CAPTURE,
                                 0/*SND_PCM_ASYNC*/)) < 0) {

        qWarning( "QAudioInput: snd_pcm_open: error %d", err);

        rc = false;
    }
    else {
        snd_pcm_hw_params_t *hwparams;

        // We want non-blocking mode.
        snd_pcm_nonblock(handle, 1);

        // Set the desired parameters.
        snd_pcm_hw_params_alloca(&hwparams);

        err = snd_pcm_hw_params_any(handle, hwparams);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_any: err %d", err);
        }

        err = snd_pcm_hw_params_set_access(handle, hwparams,
                                           access);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_set_access: err %d",err);
        }

        err = snd_pcm_hw_params_set_format(handle, hwparams,format);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_set_format: err %d",err);
        }

        err = snd_pcm_hw_params_set_channels(handle,hwparams,(unsigned int)channels);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_set_channels: err %d",err);
        }

        err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &freakuency, 0);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params_set_rate_near: err %d",err);
        }
        if(freakuency > 1.05 * frequency || freakuency < 0.95 * frequency) {
            qWarning("QAudioInput: warning, sample rate %i not supported by the hardware, using %u", frequency, freakuency);
        }

        if ( samplesPerBlock != -1 ) {
            // Set buffer and period sizes based on the supplied block size.
            sample_size = (snd_pcm_uframes_t)( samplesPerBlock * channels / 8 );
            err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &freakuency, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_rate_near: err %d",err);
            }
            if(freakuency > 1.05 * frequency || freakuency < 0.95 * frequency) {
                qWarning( "QAudioInput: warning, sample rate %i not supported by the hardware, using %u", frequency, freakuency);
            }

            err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err %d",err);
            }
            period_time = 1000000 * 256 / frequency;
            err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_period_time_near: err %d",err);
            }
        } else {
            // Use the largest buffer and period sizes we can.
            err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err %d",err);
            }
            period_time = 1000000 * 256 / frequency;
            err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, 0);
            if ( err < 0 ) {
                qWarning( "QAudioInput: snd_pcm_hw_params_set_period_time_near: err %d",err);
            }
       }

        err = snd_pcm_hw_params(handle, hwparams);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_hw_params: err %d",err);
        }

        int                  dir;
        unsigned int         vval, vval2;
        snd_pcm_access_t     aval;
        snd_pcm_format_t     fval;
        snd_pcm_subformat_t  sval;

        qLog(QAudioInput) << "PCM handle name = " << snd_pcm_name(handle);
        qLog(QAudioInput) << "PCM state = " << snd_pcm_state_name(snd_pcm_state(handle));

        snd_pcm_hw_params_get_access(hwparams,&aval);
        vval = (unsigned int)aval;
        if ( (int)vval != (int)access ) {
            qLog(QAudioInput) << QString("access type not set, want %1 got %2")
                       .arg(snd_pcm_access_name((snd_pcm_access_t)access))
                       .arg(snd_pcm_access_name((snd_pcm_access_t)vval));
            access = (snd_pcm_access_t)vval;
        }
        qLog(QAudioInput) << "access type = " << snd_pcm_access_name((snd_pcm_access_t)vval);

        snd_pcm_hw_params_get_format(hwparams, &fval);
        vval = (unsigned int)fval;
        if ( (int)vval != (int)format ) {
            qLog(QAudioInput) << QString("format type not set, want %1 got %2")
                       .arg(snd_pcm_format_name((snd_pcm_format_t)format))
                       .arg(snd_pcm_format_name((snd_pcm_format_t)vval));
            format = (snd_pcm_format_t)vval;
        }
        qLog(QAudioInput) << QString("format = '%1' (%2)")
            .arg(snd_pcm_format_name((snd_pcm_format_t)vval))
            .arg(snd_pcm_format_description((snd_pcm_format_t)vval))
            .toLatin1().constData();

        snd_pcm_hw_params_get_subformat(hwparams,&sval);
        vval = (unsigned int)sval;
        qLog(QAudioInput) << QString("subformat = '%1' (%2)")
            .arg(snd_pcm_subformat_name((snd_pcm_subformat_t)vval))
            .arg(snd_pcm_subformat_description((snd_pcm_subformat_t)vval))
            .toLatin1().constData();

        snd_pcm_hw_params_get_channels(hwparams, &vval);
        if ( (int)vval != (int)channels ) {
            qLog(QAudioInput) << QString("channels type not set, want %1 got %2").arg(channels).arg(vval);
            channels = vval;
        }
        qLog(QAudioInput) << "channels = " << vval;

        snd_pcm_hw_params_get_rate(hwparams, &vval, &dir);
        if ( (int)vval != (int)frequency ) {
            qLog(QAudioInput) << QString("frequency type not set, want %1 got %2").arg(frequency).arg(vval);
            frequency = vval;
        }
        qLog(QAudioInput) << "rate =" <<  vval << " bps";

        snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
        qLog(QAudioInput) << "period time =" << period_time << " us";
        snd_pcm_hw_params_get_period_size(hwparams,&period_size, &dir);
        qLog(QAudioInput) << "period size =" << (int)period_size;
        snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
        qLog(QAudioInput) << "buffer time =" << buffer_time;
        snd_pcm_hw_params_get_buffer_size(hwparams,(snd_pcm_uframes_t *) &buffer_size);
        qLog(QAudioInput) << "buffer size =" << (int)buffer_size;
        snd_pcm_hw_params_get_periods(hwparams, &vval, &dir);
        qLog(QAudioInput) << "periods per buffer =" << vval;
        snd_pcm_hw_params_get_rate_numden(hwparams, &vval, &vval2);
        qLog(QAudioInput) << QString("exact rate = %1/%2 bps").arg(vval).arg(vval2).toLatin1().constData();
        vval = snd_pcm_hw_params_get_sbits(hwparams);
        qLog(QAudioInput) << "significant bits =" << vval;
        snd_pcm_hw_params_get_tick_time(hwparams,&vval, &dir);
        qLog(QAudioInput) << "tick time =" << vval;
        vval = snd_pcm_hw_params_is_batch(hwparams);
        qLog(QAudioInput) << "is batch =" << vval;
        vval = snd_pcm_hw_params_is_block_transfer(hwparams);
        qLog(QAudioInput) << "is block transfer =" << vval;
        vval = snd_pcm_hw_params_is_double(hwparams);
        qLog(QAudioInput) << "is double =" << vval;
        vval = snd_pcm_hw_params_is_half_duplex(hwparams);
        qLog(QAudioInput) << "is half duplex =" << vval;
        vval = snd_pcm_hw_params_is_joint_duplex(hwparams);
        qLog(QAudioInput) << "is joint duplex =" << vval;
        vval = snd_pcm_hw_params_can_overrange(hwparams);
        qLog(QAudioInput) << "can overrange =" << vval;
        vval = snd_pcm_hw_params_can_mmap_sample_resolution(hwparams);
        qLog(QAudioInput) << "can mmap =" << vval;
        vval = snd_pcm_hw_params_can_pause(hwparams);
        qLog(QAudioInput) << "can pause =" << vval;
        vval = snd_pcm_hw_params_can_resume(hwparams);
        qLog(QAudioInput) << "can resume =" << vval;
        vval = snd_pcm_hw_params_can_sync_start(hwparams);
        qLog(QAudioInput) << "can sync start =" << vval;

        snd_pcm_sw_params_t *swparams;
        snd_pcm_sw_params_alloca(&swparams);
        err = snd_pcm_sw_params_current(handle, swparams);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params_current: err %d",err);
        }
        err = snd_pcm_sw_params_set_start_threshold(handle,swparams,period_size);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params_set_start_threshold: err %d",err);
        }
        err = snd_pcm_sw_params_set_avail_min(handle, swparams,period_size);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params_set_avail_min: err %d",err);
        }
        err = snd_pcm_sw_params_set_xfer_align(handle, swparams, 1);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params_set_xfer_align: err %d",err);
        }
        err = snd_pcm_sw_params(handle, swparams);
        if ( err < 0 ) {
            qWarning( "QAudioInput: snd_pcm_sw_params: err %d",err);
        }

        snd_pcm_prepare(handle);
        snd_pcm_start(handle);

        int     count = snd_pcm_poll_descriptors_count(handle);
        pollfd  *pfds = new pollfd[count];

        snd_pcm_poll_descriptors(handle, pfds, count);

        for (int i = 0; i < count; ++i)
        {
            if ((pfds[i].events & POLLIN) != 0) {
                notifier = new QSocketNotifier(pfds[i].fd, QSocketNotifier::Read);
                QObject::connect(notifier,
                                 SIGNAL(activated(int)),
                                 input,
                                 SIGNAL(readyRead()));

                break;
            }
        }

        if (notifier == NULL) {
            rc = false;
        }

        delete pfds;
    }

    return rc;
}
int snd_pcm_generic_start(snd_pcm_t *pcm)
{
	snd_pcm_generic_t *generic = pcm->private_data;
	return snd_pcm_start(generic->slave);
}
예제 #5
0
void *CallbackThread( void *userData )
{
    PaAlsaStream *stream = (PaAlsaStream*)userData;
    pthread_cleanup_push( &Stop, stream );   // Execute Stop on exit

    if( stream->pcm_playback )
        snd_pcm_start( stream->pcm_playback );
    else if( stream->pcm_capture )
        snd_pcm_start( stream->pcm_capture );

    while(1)
    {
        int frames_avail;
        int frames_got;

        PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
        int callbackResult;
        int framesProcessed;

        pthread_testcancel();
        {
            /* calculate time info */
            snd_timestamp_t capture_timestamp;
            snd_timestamp_t playback_timestamp;
            snd_pcm_status_t *capture_status;
            snd_pcm_status_t *playback_status;
            snd_pcm_status_alloca( &capture_status );
            snd_pcm_status_alloca( &playback_status );

            if( stream->pcm_capture )
            {
                snd_pcm_status( stream->pcm_capture, capture_status );
                snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
            }
            if( stream->pcm_playback )
            {
                snd_pcm_status( stream->pcm_playback, playback_status );
                snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
            }

            /* Hmm, we potentially have both a playback and a capture timestamp.
             * Hopefully they are the same... */
            if( stream->pcm_capture && stream->pcm_playback )
            {
                float capture_time = capture_timestamp.tv_sec +
                                     ((float)capture_timestamp.tv_usec/1000000);
                float playback_time= playback_timestamp.tv_sec +
                                     ((float)playback_timestamp.tv_usec/1000000);
                if( fabsf(capture_time-playback_time) > 0.01 )
                    PA_DEBUG(("Capture time and playback time differ by %f\n", fabsf(capture_time-playback_time)));
                timeInfo.currentTime = capture_time;
            }
            else if( stream->pcm_playback )
            {
                timeInfo.currentTime = playback_timestamp.tv_sec +
                                       ((float)playback_timestamp.tv_usec/1000000);
            }
            else
            {
                timeInfo.currentTime = capture_timestamp.tv_sec +
                                       ((float)capture_timestamp.tv_usec/1000000);
            }

            if( stream->pcm_capture )
            {
                snd_pcm_sframes_t capture_delay = snd_pcm_status_get_delay( capture_status );
                timeInfo.inputBufferAdcTime = timeInfo.currentTime -
                    (float)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
            }

            if( stream->pcm_playback )
            {
                snd_pcm_sframes_t playback_delay = snd_pcm_status_get_delay( playback_status );
                timeInfo.outputBufferDacTime = timeInfo.currentTime +
                    (float)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
            }
        }


        /*
            IMPLEMENT ME:
                - handle buffer slips
        */

        /*
            depending on whether the host buffers are interleaved, non-interleaved
            or a mixture, you will want to call PaUtil_ProcessInterleavedBuffers(),
            PaUtil_ProcessNonInterleavedBuffers() or PaUtil_ProcessBuffers() here.
        */

        framesProcessed = frames_avail = wait( stream );

        while( frames_avail > 0 )
        {
            //PA_DEBUG(( "%d frames available\n", frames_avail ));

            /* Now we know the soundcard is ready to produce/receive at least
             * one period.  We just need to get the buffers for the client
             * to read/write. */
            PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
                    0 /* @todo pass underflow/overflow flags when necessary */ );

            frames_got = setup_buffers( stream, frames_avail );


            PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );

            callbackResult = paContinue;

            /* this calls the callback */

            framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
                                                          &callbackResult );

            PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );

            /* inform ALSA how many frames we wrote */

            if( stream->pcm_capture )
                snd_pcm_mmap_commit( stream->pcm_capture, stream->capture_offset, frames_got );

            if( stream->pcm_playback )
                snd_pcm_mmap_commit( stream->pcm_playback, stream->playback_offset, frames_got );

            if( callbackResult != paContinue )
                break;

            frames_avail -= frames_got;
        }


        /*
            If you need to byte swap outputBuffer, you can do it here using
            routines in pa_byteswappers.h
        */

        if( callbackResult != paContinue )
        {
            stream->callback_finished = 1;
            stream->callbackAbort = (callbackResult == paAbort);

            pthread_exit( NULL );
        }
    }

    /* This code is unreachable, but important to include regardless because it
     * is possibly a macro with a closing brace to match the opening brace in
     * pthread_cleanup_push() above.  The documentation states that they must
     * always occur in pairs. */

    pthread_cleanup_pop( 1 );
}
예제 #6
0
파일: main.c 프로젝트: texane/aspect
static int pcm_start(pcm_handle_t* pcm)
{
  return snd_pcm_start(pcm->pcm);
}
예제 #7
0
/*****************************************************************************
 * OpenAudioDev: open and set up the audio device and probe for capabilities
 *****************************************************************************/
static int OpenAudioDevAlsa( demux_t *p_demux, const char *psz_device )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    p_sys->p_alsa_pcm = NULL;
    snd_pcm_hw_params_t *p_hw_params = NULL;
    snd_pcm_uframes_t buffer_size;
    snd_pcm_uframes_t chunk_size;

    /* ALSA */
    int i_err;

    if( ( i_err = snd_pcm_open( &p_sys->p_alsa_pcm, psz_device,
        SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK ) ) < 0)
    {
        msg_Err( p_demux, "Cannot open ALSA audio device %s (%s)",
                 psz_device, snd_strerror( i_err ) );
        goto adev_fail;
    }

    if( ( i_err = snd_pcm_nonblock( p_sys->p_alsa_pcm, 1 ) ) < 0)
    {
        msg_Err( p_demux, "Cannot set ALSA nonblock (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Begin setting hardware parameters */

    if( ( i_err = snd_pcm_hw_params_malloc( &p_hw_params ) ) < 0 )
    {
        msg_Err( p_demux,
                 "ALSA: cannot allocate hardware parameter structure (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    if( ( i_err = snd_pcm_hw_params_any( p_sys->p_alsa_pcm, p_hw_params ) ) < 0 )
    {
        msg_Err( p_demux,
                "ALSA: cannot initialize hardware parameter structure (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set Interleaved access */
    if( ( i_err = snd_pcm_hw_params_set_access( p_sys->p_alsa_pcm, p_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED ) ) < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set access type (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set 16 bit little endian */
    if( ( i_err = snd_pcm_hw_params_set_format( p_sys->p_alsa_pcm, p_hw_params, SND_PCM_FORMAT_S16_LE ) ) < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set sample format (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set sample rate */
    i_err = snd_pcm_hw_params_set_rate_near( p_sys->p_alsa_pcm, p_hw_params, &p_sys->i_sample_rate, NULL );
    if( i_err < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set sample rate (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set channels */
    unsigned int channels = p_sys->b_stereo ? 2 : 1;
    if( ( i_err = snd_pcm_hw_params_set_channels( p_sys->p_alsa_pcm, p_hw_params, channels ) ) < 0 )
    {
        channels = ( channels==1 ) ? 2 : 1;
        msg_Warn( p_demux, "ALSA: cannot set channel count (%s). "
                  "Trying with channels=%d",
                  snd_strerror( i_err ),
                  channels );
        if( ( i_err = snd_pcm_hw_params_set_channels( p_sys->p_alsa_pcm, p_hw_params, channels ) ) < 0 )
        {
            msg_Err( p_demux, "ALSA: cannot set channel count (%s)",
                     snd_strerror( i_err ) );
            goto adev_fail;
        }
        p_sys->b_stereo = ( channels == 2 );
    }

    /* Set metrics for buffer calculations later */
    unsigned int buffer_time;
    if( ( i_err = snd_pcm_hw_params_get_buffer_time_max(p_hw_params, &buffer_time, 0) ) < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot get buffer time max (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }
    if( buffer_time > 500000 ) buffer_time = 500000;

    /* Set period time */
    unsigned int period_time = buffer_time / 4;
    i_err = snd_pcm_hw_params_set_period_time_near( p_sys->p_alsa_pcm, p_hw_params, &period_time, 0 );
    if( i_err < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set period time (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Set buffer time */
    i_err = snd_pcm_hw_params_set_buffer_time_near( p_sys->p_alsa_pcm, p_hw_params, &buffer_time, 0 );
    if( i_err < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set buffer time (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Apply new hardware parameters */
    if( ( i_err = snd_pcm_hw_params( p_sys->p_alsa_pcm, p_hw_params ) ) < 0 )
    {
        msg_Err( p_demux, "ALSA: cannot set hw parameters (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    /* Get various buffer metrics */
    snd_pcm_hw_params_get_period_size( p_hw_params, &chunk_size, 0 );
    snd_pcm_hw_params_get_buffer_size( p_hw_params, &buffer_size );
    if( chunk_size == buffer_size )
    {
        msg_Err( p_demux,
                 "ALSA: period cannot equal buffer size (%lu == %lu)",
                 chunk_size, buffer_size);
        goto adev_fail;
    }

    int bits_per_sample = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE);
    int bits_per_frame = bits_per_sample * channels;

    p_sys->i_alsa_chunk_size = chunk_size;
    p_sys->i_alsa_frame_size = bits_per_frame / 8;
    p_sys->i_max_frame_size = chunk_size * bits_per_frame / 8;

    snd_pcm_hw_params_free( p_hw_params );
    p_hw_params = NULL;

    /* Prep device */
    if( ( i_err = snd_pcm_prepare( p_sys->p_alsa_pcm ) ) < 0 )
    {
        msg_Err( p_demux,
                 "ALSA: cannot prepare audio interface for use (%s)",
                 snd_strerror( i_err ) );
        goto adev_fail;
    }

    snd_pcm_start( p_sys->p_alsa_pcm );

    return VLC_SUCCESS;

 adev_fail:

    if( p_hw_params ) snd_pcm_hw_params_free( p_hw_params );
    if( p_sys->p_alsa_pcm ) snd_pcm_close( p_sys->p_alsa_pcm );
    p_sys->p_alsa_pcm = NULL;

    return VLC_EGENERIC;

}
예제 #8
0
    /* return 0 on success */
int alsa_open_audio(int naudioindev, int *audioindev, int nchindev,
    int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
    int *choutdev, int rate, int blocksize)
{
    int err, inchans = 0, outchans = 0, subunitdir;
    char devname[512];
    snd_output_t* out;
    int frag_size = (blocksize ? blocksize : ALSA_DEFFRAGSIZE);
    int nfrags, i, iodev, dev2;
    int wantinchans, wantoutchans, device;

    nfrags = sys_schedadvance * (float)rate / (1e6 * frag_size);
        /* save our belief as to ALSA's buffer size for later */
    alsa_buf_samps = nfrags * frag_size;
    alsa_nindev = alsa_noutdev = 0;
    alsa_jittermax = ALSA_DEFJITTERMAX;

    if (sys_verbose)
        post("audio buffer set to %d", (int)(0.001 * sys_schedadvance));

    for (iodev = 0; iodev < naudioindev; iodev++)
    {
        alsa_numbertoname(audioindev[iodev], devname, 512);
        err = snd_pcm_open(&alsa_indev[alsa_nindev].a_handle, devname,
            SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
        check_error(err, 0, "snd_pcm_open");
        if (err < 0)
            continue;
        alsa_indev[alsa_nindev].a_devno = audioindev[iodev];
        snd_pcm_nonblock(alsa_indev[alsa_nindev].a_handle, 1);
        if (sys_verbose)
            post("opened input device name %s", devname);
        alsa_nindev++;
    }
    for (iodev = 0; iodev < naudiooutdev; iodev++)
    {
        alsa_numbertoname(audiooutdev[iodev], devname, 512);
        err = snd_pcm_open(&alsa_outdev[alsa_noutdev].a_handle, devname,
            SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
        check_error(err, 1, "snd_pcm_open");
        if (err < 0)
            continue;
        alsa_outdev[alsa_noutdev].a_devno = audiooutdev[iodev];
        snd_pcm_nonblock(alsa_outdev[alsa_noutdev].a_handle, 1);
        alsa_noutdev++;
    }
    if (!alsa_nindev && !alsa_noutdev)
        goto blewit;

        /* If all the open devices support mmap_noninterleaved, let's call
        Wini's code in s_audio_alsamm.c */
    alsa_usemmap = 1;
    for (iodev = 0; iodev < alsa_nindev; iodev++)
        if (!alsaio_canmmap(&alsa_indev[iodev]))
            alsa_usemmap = 0;
    for (iodev = 0; iodev < alsa_noutdev; iodev++)
        if (!alsaio_canmmap(&alsa_outdev[iodev]))
            alsa_usemmap = 0;
    if (alsa_usemmap)
    {
        post("using mmap audio interface");
        if (alsamm_open_audio(rate, blocksize))
            goto blewit;
        else return (0);
    }
    for (iodev = 0; iodev < alsa_nindev; iodev++)
    {
        int channels = chindev[iodev];
        if (alsaio_setup(&alsa_indev[iodev], 0, &channels, &rate,
            nfrags, frag_size) < 0)
                goto blewit;
        inchans += channels;
    }
    for (iodev = 0; iodev < alsa_noutdev; iodev++)
    {
        int channels = choutdev[iodev];
        if (alsaio_setup(&alsa_outdev[iodev], 1, &channels, &rate,
            nfrags, frag_size) < 0)
                goto blewit;
        outchans += channels;
    }
    if (!inchans && !outchans)
        goto blewit;

    for (iodev = 0; iodev < alsa_nindev; iodev++)
        snd_pcm_prepare(alsa_indev[iodev].a_handle);
    for (iodev = 0; iodev < alsa_noutdev; iodev++)
        snd_pcm_prepare(alsa_outdev[iodev].a_handle);

        /* if duplex we can link the channels so they start together */
    for (iodev = 0; iodev < alsa_nindev; iodev++)
        for (dev2 = 0; dev2 < alsa_noutdev; dev2++)
    {
        if (alsa_indev[iodev].a_devno == alsa_outdev[iodev].a_devno)
        {
            snd_pcm_link(alsa_indev[iodev].a_handle,
                alsa_outdev[iodev].a_handle);
        }
    }

        /* allocate the status variables */
    if (!alsa_status)
    {
        err = snd_pcm_status_malloc(&alsa_status);
        check_error(err, -1, "snd_pcm_status_malloc");
    }

        /* fill the buffer with silence and prime the output FIFOs.  This
        should automatically start the output devices. */
    memset(alsa_snd_buf, 0, alsa_snd_bufsize);

    if (outchans)
    {
        i = (frag_size * nfrags)/DEFDACBLKSIZE + 1;
        while (i--)
        {
            for (iodev = 0; iodev < alsa_noutdev; iodev++)
                snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf,
                    DEFDACBLKSIZE);
        }
    }
    if (inchans)
    {
            /* some of the ADC devices might already have been started by
            starting the outputs above, but others might still need it. */
        for (iodev = 0; iodev < alsa_nindev; iodev++)
            if (snd_pcm_state(alsa_indev[iodev].a_handle)
                != SND_PCM_STATE_RUNNING)
                    if ((err = snd_pcm_start(alsa_indev[iodev].a_handle)) < 0)
                        check_error(err, -1, "input start failed");
    }
    return (0);
blewit:
    STUFF->st_inchannels = 0;
    STUFF->st_outchannels = 0;
    alsa_close_audio();
    return (1);
}
예제 #9
0
void AlsaLayer::startCaptureStream()
{
    if (captureHandle_ and not is_capture_running_)
        if (ALSA_CALL(snd_pcm_start(captureHandle_), "Couldn't start capture") >= 0)
            is_capture_running_ = true;
}
예제 #10
0
파일: tinker.c 프로젝트: siddharthcs94/test
int main()
{
char *filename = "44k.wav";
 SF_INFO sfinfo;
  SNDFILE *f;
  f = sf_open(filename,SFM_READ, &sfinfo);
 printf("\nCHECK RATE %d \n",sfinfo.samplerate);
printf("\nCHECK CHANNELS %d \n",sfinfo.channels);
printf("\nNumber of frames %ld \n",sfinfo.frames);

int j; 


snd_pcm_t *pcm_handle;
char *pcm_name;
unsigned int err;
//pcm_name = "default";
pcm_name = "plughw:0,0";
snd_pcm_hw_params_t *hwparams;
unsigned int rate = sfinfo.samplerate;


unsigned int channels = sfinfo.channels;
unsigned int exact_rate;


 snd_pcm_uframes_t frames, offset;
 snd_pcm_sframes_t commitres, avail,size=170;
 const snd_pcm_channel_area_t *areas;
 unsigned char *ptr[2];
 
snd_pcm_format_t stream = SND_PCM_FORMAT_S16_LE;


err=snd_pcm_open(&pcm_handle,pcm_name,SND_PCM_STREAM_PLAYBACK,0);
         
         if(err<0)       
                 {       
                         perror("\nCannot open PCM device\n");
                         exit(0);
           	}


if(snd_pcm_hw_params_malloc(&hwparams)<0)
	{
		perror("\nMemory cannot be allocated\n");
		exit(0);
	}


if(snd_pcm_hw_params_any(pcm_handle,hwparams)<0)
	{
		perror("\nUnable to set any HW configuration to device\n");
		exit(0);
	}

exact_rate = rate;

if(snd_pcm_hw_params_set_rate_near(pcm_handle,  hwparams,  &exact_rate, 0)<0)
	{
		printf("\nUnable to set rate %u instead rate used is %u \n",rate,exact_rate);
	}
rate = exact_rate;
printf("\nExact rate is %u \n",rate);


if(snd_pcm_hw_params_set_channels(pcm_handle,  hwparams,  channels),0)
	{
		perror("\nUnable to set channels\n");
		exit(0);
	}
if(snd_pcm_hw_params_set_format(pcm_handle,  hwparams,  stream)<0)
	{
		perror("\nUnable to set format\n");
		exit(0);
	}

if(snd_pcm_hw_params_set_access(pcm_handle,  hwparams,  SND_PCM_ACCESS_MMAP_INTERLEAVED)<0)
	{
		perror("\nUnable to set access\n");
		exit(0);
	}



snd_pcm_sframes_t period_size;

snd_pcm_hw_params_get_period_size(hwparams, &period_size,0);
	
printf("\nPeriod size is %ld \n",period_size);



err = snd_pcm_hw_params(pcm_handle,hwparams);
if(err<0)
	{
		perror("\nHW params cannot be set\n");
		exit(0);
	}


snd_pcm_hw_params_get_period_size(hwparams,&period_size,0);
printf("\nObtained Period size = %ld \n",period_size);

size = period_size;

snd_pcm_hw_params_get_buffer_size(hwparams,&frames);
printf("\nObtained buffer size is %ld \n",frames);


int ret = open(filename,O_RDONLY);
if(ret<0)
	{
		perror("\nFile cannot be opened\n");
		exit(0);
	}



int k=0;
int i;

while(1)
	{
	k++;
	if(k==2)
		{
			err = snd_pcm_start(pcm_handle);
			if(err<0)
				{
					perror("\nError starting PCM device\n");
					exit(1);
				}
		}
 
		
	avail = snd_pcm_avail_update(pcm_handle);
		if(avail<frames)
			{
				err = snd_pcm_prepare(pcm_handle);
				if(err<0)
					{
						perror("\nNo frames available\n");
						exit(0);
					}
		}
//	printf("\nFrames available %ld\n",avail);

	
	size=period_size;


	while(size>0)
		{
			

			frames = size;

			err = snd_pcm_mmap_begin(pcm_handle,  &areas,  &offset,  &frames);
						
			 if(err<0)
				{
					perror("\nMMAP cannot assign areas\n");
					exit(0);
				}
			

			for(i=0;i<1;i++)
			{
			ptr[i] = (unsigned char *)areas[i].addr + areas[i].first/8 + offset*(areas[i].step/8) ;
		//	printf("\nCheck\n");


				if(ptr[i]==NULL)
					{
						perror("\nPointer cannot point to memory\n");
						exit(0);
					}

			}


			for(i=0;i<1;i++)
			if(read(ret, ptr[i], frames*4)>0)
				{
					
				
				}
			else 
				{
					perror("\nFile cannot be opened\n");
					exit(0);
				}

				      commitres = snd_pcm_mmap_commit(pcm_handle,  offset,  frames);
 
                                         if(commitres<0)
                                                 {
                                                         err = snd_pcm_prepare(pcm_handle);
 
                                                         if(err<0)
                                                                 {
                                                                 perror("\nFrames cannot be committed\n");
                                                                exit(0);
                                                                }
						
						}

				else size-=frames;
			snd_pcm_wait(pcm_handle,1000);


		}//END OF "while(size>0)" LOOP

		}//END OF OUTER WHILE LOOP

}
예제 #11
0
static void *Thread (void *data)
{
    demux_t *demux = data;
    demux_sys_t *sys = demux->p_sys;
    snd_pcm_t *pcm = sys->pcm;
    size_t bytes;
    int canc, val;

    canc = vlc_savecancel ();
    bytes = snd_pcm_frames_to_bytes (pcm, sys->period_size);
    val = snd_pcm_start (pcm);
    if (val)
    {
        msg_Err (demux, "cannot prepare device: %s", snd_strerror (val));
        return NULL;
    }

    for (;;)
    {
        block_t *block = block_Alloc (bytes);
        if (unlikely(block == NULL))
            break;

        /* Wait for data */
        Poll (pcm, canc);

        /* Read data */
        snd_pcm_sframes_t frames, delay;
        mtime_t pts;

        frames = snd_pcm_readi (pcm, block->p_buffer, sys->period_size);
        pts = mdate ();
        if (frames < 0)
        {
            if (frames == -EAGAIN)
                continue;

            val = snd_pcm_recover (pcm, frames, 1);
            if (val == 0)
            {
                msg_Warn (demux, "cannot read samples: %s",
                          snd_strerror (frames));
                continue;
            }
            msg_Err (demux, "cannot recover record stream: %s",
                     snd_strerror (val));
            DumpDeviceStatus (demux, pcm);
            break;
        }

        /* Compute time stamp */
        if (snd_pcm_delay (pcm, &delay))
            delay = 0;
        delay += frames;
        pts -= (CLOCK_FREQ * delay) / sys->rate;

        block->i_buffer = snd_pcm_frames_to_bytes (pcm, frames);
        block->i_nb_samples = frames;
        block->i_pts = pts;
        block->i_length = (CLOCK_FREQ * frames) / sys->rate;

        es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
        es_out_Send (demux->out, sys->es, block);
    }
    return NULL;
}
예제 #12
0
파일: dscapture.c 프로젝트: mikekap/wine
/** Fill buffers, for starting and stopping
 * Alsa won't start playing until everything is filled up
 * This also updates mmap_pos
 *
 * Returns: Amount of periods in use so snd_pcm_avail_update
 * doesn't have to be called up to 4x in GetPosition()
 */
static snd_pcm_uframes_t CommitAll(IDsCaptureDriverBufferImpl *This, DWORD forced)
{
    const snd_pcm_channel_area_t *areas;
    snd_pcm_uframes_t used;
    const snd_pcm_uframes_t commitahead = This->mmap_buflen_frames;

    used = This->mmap_buflen_frames - snd_pcm_avail_update(This->pcm);
    TRACE("%p needs to commit to %lu, used: %lu\n", This, commitahead, used);
    if (used < commitahead && (forced || This->play_looping))
    {
        snd_pcm_uframes_t done, putin = commitahead - used;
        if (This->mmap)
        {
            snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
            CopyData(This, This->mmap_pos, putin);
            done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);

            This->mmap_pos += done;
            used += done;
            putin = commitahead - used;

            if (This->mmap_pos == This->mmap_buflen_frames && (snd_pcm_sframes_t)putin > 0 && This->play_looping)
            {
                This->mmap_ofs_bytes += snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
                This->mmap_ofs_bytes %= This->mmap_buflen_bytes;

                snd_pcm_mmap_begin(This->pcm, &areas, &This->mmap_pos, &putin);
                CopyData(This, This->mmap_pos, putin);
                done = snd_pcm_mmap_commit(This->pcm, This->mmap_pos, putin);

                This->mmap_pos += done;
                used += done;
            }
        }
        else
        {
            DWORD pos;
            snd_pcm_sframes_t ret;

            snd_pcm_uframes_t cap = snd_pcm_bytes_to_frames(This->pcm, This->mmap_buflen_bytes);
            pos = realpos_to_fakepos(This, This->mmap_pos);
            if (This->mmap_pos + putin > cap)
                putin = cap - This->mmap_pos;
            ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
            if (ret == -EPIPE)
            {
                WARN("Underrun occurred\n");
                snd_pcm_prepare(This->pcm);
                ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
                snd_pcm_start(This->pcm);
            }
            if (ret < 0)
            {
                WARN("Committing data: %ld / %s (%ld)\n", ret, snd_strerror(ret), putin);
                ret = 0;
            }
            This->mmap_pos += ret;
            used += ret;
            /* At this point mmap_pos may be >= This->mmap_pos this is harmless
             * realpos_to_fakepos handles it well, and below it is truncated
             */

            putin = commitahead - used;
            if (putin > 0)
            {
                pos = realpos_to_fakepos(This, This->mmap_pos);
                ret = snd_pcm_readi(This->pcm, This->presented_buffer + pos, putin);
                if (ret > 0)
                {
                    This->mmap_pos += ret;
                    used += ret;
                }
            }
        }

    }

    if (This->mmap_pos >= This->mmap_buflen_frames)
    {
        This->mmap_ofs_bytes += snd_pcm_frames_to_bytes(This->pcm, This->mmap_buflen_frames);
        This->mmap_ofs_bytes %= This->mmap_buflen_bytes;
        This->mmap_pos -= This->mmap_buflen_frames;
    }

    return used;
}
/// Open and init default sound card params
int init_soundcard()
{
	int err = 0;

	if ((err = snd_pcm_open(&capture_handle, snd_device,
			SND_PCM_STREAM_CAPTURE, 0)) < 0)
	{
		fprintf(stderr, "cannot open audio device %s (%s, %d)\n",
				snd_device, snd_strerror(err), err);
		return OPEN_ERROR;
	}

	if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
	{
		fprintf(
				stderr,
				"cannot allocate hardware parameter structure (%s, %d)\n",
				snd_strerror(err), err);
		return MALLOC_ERROR;
	}

	if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0)
	{
		fprintf(
				stderr,
				"cannot initialize hardware parameter structure (%s, %d)\n",
				snd_strerror(err), err);
		return ANY_ERROR;
	}

	if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params,
			SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
	{
		fprintf(stderr, "cannot set access type (%s, %d)\n",
				snd_strerror(err), err);
		return ACCESS_ERROR;
	}

	if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params,
			SND_PCM_FORMAT_S16_LE)) < 0)
	{
		fprintf(stderr, "cannot set sample format (%s, %d)\n",
				snd_strerror(err), err);
		return FORMAT_ERROR;
	}

	if ((err = snd_pcm_hw_params_set_rate_near(capture_handle, hw_params,
			&srate, 0)) < 0)
	{
		fprintf(stderr, "cannot set sample rate (%s, %d)\n",
				snd_strerror(err), err);
		return RATE_ERROR;
	}

	if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, nchan))
			< 0)
	{
		fprintf(stderr, "cannot set channel count (%s, %d)\n",
				snd_strerror(err), err);
		return CHANNELS_ERROR;
	}

	if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0)
	{
		fprintf(stderr, "cannot set parameters (%s, %d)\n",
				snd_strerror(err), err);
		return PARAMS_ERROR;
	}

	if ((err = snd_pcm_prepare(capture_handle)) < 0)
	{
		fprintf(
				stderr,
				"cannot prepare audio interface for use (%s, %d)\n",
				snd_strerror(err), err);
		return PREPARE_ERROR;
	}

	  //fprintf(stderr, "Capture handle1: %x\n", capture_handle);
	  //fprintf(stderr, "Capture state1: %d\n", snd_pcm_state(capture_handle));

	  // Start reading data from sound card
	  if ((err = snd_pcm_start(capture_handle)) < 0)
	  {
		  fprintf(stderr, "cannot start soundcard (%s, %d)\n", snd_strerror(err),
				  err);
		  return START_ERROR;
	  }

	  //fprintf(stderr, "Capture handle2: %x\n", capture_handle);
	  //fprintf(stderr, "Capture state2: %d\n", snd_pcm_state(capture_handle));

	/*
	fprintf(stderr, "%s\n", "Parameters of PCM:");
	fprintf(stderr, "%x\n", capture_handle);
	fprintf(stderr, "%s\n", snd_pcm_name(capture_handle));
	fprintf(stderr, "%d\n", snd_pcm_type(capture_handle));
	fprintf(stderr, "%d\n", snd_pcm_stream(capture_handle));
	fprintf(stderr, "%d\n", snd_pcm_poll_descriptors_count(capture_handle));
	fprintf(stderr, "%d\n", snd_pcm_state(capture_handle));
	fprintf(stderr, "%d\n", snd_pcm_avail(capture_handle));
	fprintf(stderr, "%d\n", snd_pcm_avail_update(capture_handle));
	fprintf(stderr, "%d\n", snd_pcm_rewindable(capture_handle));
	fprintf(stderr, "%d\n", snd_pcm_forwardable(capture_handle));
	fprintf(stderr, "%s\n", "-------------------------------------");
	fprintf(stderr, "%d\n", snd_pcm_info_malloc(&s_info));
	fprintf(stderr, "%d\n", snd_pcm_info(capture_handle, s_info));
	fprintf(stderr, "%d\n", snd_pcm_info_get_device(s_info));
	fprintf(stderr, "%d\n", snd_pcm_info_get_subdevice(s_info));
	fprintf(stderr, "%d\n", snd_pcm_info_get_stream(s_info));
	fprintf(stderr, "%d\n", snd_pcm_info_get_card(s_info));
	fprintf(stderr, "%s\n", snd_pcm_info_get_id(s_info));
	fprintf(stderr, "%s\n", snd_pcm_info_get_name(s_info));
	fprintf(stderr, "%s\n", snd_pcm_info_get_subdevice_name(s_info));
	fprintf(stderr, "%d\n", snd_pcm_info_get_class(s_info));
	fprintf(stderr, "%d\n", snd_pcm_info_get_subclass(s_info));
	fprintf(stderr, "%d\n", snd_pcm_info_get_subdevices_count(s_info));
	fprintf(stderr, "%d\n", snd_pcm_info_get_subdevices_avail(s_info));
	fprintf(stderr, "%s\n", "-------------------------------------");
	fprintf(stderr, "%d\n", snd_pcm_hw_params_current(capture_handle, hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_is_double(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_is_batch(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_is_block_transfer(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_is_monotonic(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_can_overrange(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_can_pause(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_can_resume(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_is_half_duplex(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_is_joint_duplex(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_can_sync_start(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_can_disable_period_wakeup(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_sbits(hw_params));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_fifo_size(hw_params));
	fprintf(stderr, "%s\n", "-------------------------------------");
	unsigned int *tmp1 = (unsigned int *)malloc(sizeof(unsigned int));
	int *tmp2 = (int *)malloc(sizeof(int));
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_channels(hw_params, tmp1)); fprintf(stderr, "%d\n", *tmp1);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_channels_min(hw_params, tmp1)); fprintf(stderr, "%d\n", *tmp1);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_channels_max(hw_params, tmp1)); fprintf(stderr, "%d\n", *tmp1);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_rate(hw_params, tmp1, tmp2)); fprintf(stderr, "%d\n", *tmp1 ,  *tmp2);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_rate_min(hw_params, tmp1, tmp2)); fprintf(stderr, "%d\n", *tmp1 ,  *tmp2);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_rate_max(hw_params, tmp1, tmp2)); fprintf(stderr, "%d\n", *tmp1 ,  *tmp2);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_rate_resample(capture_handle, hw_params, tmp1)); fprintf(stderr, "%d\n", *tmp1);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_export_buffer(capture_handle, hw_params, tmp1)); fprintf(stderr, "%d\n", *tmp1);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_period_wakeup(capture_handle, hw_params, tmp1)); fprintf(stderr, "%d\n", *tmp1);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_period_time(hw_params, tmp1, tmp2)); fprintf(stderr, "%d\n", *tmp1 ,  *tmp2);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_period_time_min(hw_params, tmp1, tmp2)); fprintf(stderr, "%d\n", *tmp1 ,  *tmp2);
	fprintf(stderr, "%d\n", snd_pcm_hw_params_get_period_time_max(hw_params, tmp1, tmp2)); fprintf(stderr, "%d\n", *tmp1 ,  *tmp2);
	*/

	snd_pcm_hw_params_free(hw_params);
	/*
	snd_pcm_info_free(s_info);
	free(tmp1);
	free(tmp2);
	*/

	return NO_ERROR;
}
예제 #14
0
int audio_alsa_init()
{
	int fd, err;
	char *pcm_rate;
	char tmp_name[20];

	init_rec_buffer();

	/* Create a temporary filename for our FIFO,
	 * Use mkstemp() instead of mktemp() although we need a FIFO not a
	 * regular file. We do this since glibc barfs at mktemp() and this
	 * scares the users :-)
	 */
	strcpy(tmp_name, "/tmp/lircXXXXXX");
	fd = mkstemp(tmp_name);
	close(fd);

	/* Start the race! */
	unlink(tmp_name);
	if (mknod(tmp_name, S_IFIFO | S_IRUSR | S_IWUSR, 0)) {
		logprintf(LOG_ERR, "could not create FIFO %s", tmp_name);
		logperror(LOG_ERR, "audio_alsa_init ()");
		return 0;
	}
	/* Phew, we won the race ... */

	/* Open the pipe and hand it to LIRC ... */
	hw.fd = open(tmp_name, O_RDWR);
	if (hw.fd < 0) {
		logprintf(LOG_ERR, "could not open pipe %s", tmp_name);
		logperror(LOG_ERR, "audio_alsa_init ()");
error:		unlink(tmp_name);
		audio_alsa_deinit();
		return 0;
	}

	/* Open the other end of the pipe and hand it to ALSA code.
	 * We're opening it in non-blocking mode to avoid lockups.
	 */
	alsa_hw.fd = open(tmp_name, O_RDWR | O_NONBLOCK);
	/* Ok, we don't need the FIFO visible in the filesystem anymore ... */
	unlink(tmp_name);

	/* Examine the device name, if it contains a sample rate */
	strncpy(tmp_name, hw.device, sizeof(tmp_name) - 1);
	pcm_rate = strchr(tmp_name, '@');
	if (pcm_rate) {
		int rate;
		char *stereo_channel;

		/* Examine if we need to capture in stereo
		 * looking for an 'l' or 'r' character to indicate
		 * which channel to look at.*/
		stereo_channel = strchr(pcm_rate, ',');

		if (stereo_channel) {

			/* Syntax in device string indicates we need
			   to use stereo */
			alsa_hw.num_channels = 2;
			/* As we are requesting stereo now, use the
			   more common signed 16bit samples */
			alsa_hw.format = SND_PCM_FORMAT_S16_LE;

			if (stereo_channel[1] == 'l') {
				alsa_hw.channel = 0;
			} else if (stereo_channel[1] == 'r') {
				alsa_hw.channel = 1;
			} else {
				logperror(LOG_WARNING,
					  "dont understand which channel to use - defaulting to left\n");
			}
		}

		/* Remove the sample rate from device name (and
		   channel indicator if present) */
		*pcm_rate++ = 0;
		/* See if rate is meaningful */
		rate = atoi(pcm_rate);
		if (rate > 0) {
			alsa_hw.rate = rate;
		}
	}

	/* Open the audio card in non-blocking mode */
	err = snd_pcm_open(&alsa_hw.handle, tmp_name, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
	if (err < 0) {
		logprintf(LOG_ERR, "could not open audio device %s: %s", hw.device, snd_strerror(err));
		logperror(LOG_ERR, "audio_alsa_init ()");
		goto error;
	}

	/* Set up the I/O signal handler */
	if (alsa_error
	    ("async_add_handler", snd_async_add_pcm_handler(&alsa_hw.sighandler, alsa_hw.handle, alsa_sig_io, NULL)))
		goto error;

	/* Set sampling parameters */
	if (alsa_set_hwparams(alsa_hw.handle))
		goto error;

	LOGPRINTF(LOG_INFO, "hw_audio_alsa: Using device '%s', sampling rate %dHz\n", tmp_name, alsa_hw.rate);

	/* Start sampling data */
	if (alsa_error("start", snd_pcm_start(alsa_hw.handle)))
		goto error;

	return 1;
}
예제 #15
0
int main(int argc, char* argv[])
{
	int df, wf;
	
	if(argc<2)
	{
		printf("Usage: %s DM-file [wav-file]\n",argv[0]);
		exit(0);
	}
	dminfo=malloc(sizeof(dmarg));
	wi=malloc(sizeof(wavinfo));
	if(!dminfo||!wi)
	{
		printf("Memory Allocation Error!\n");
		exit(0);
	}		
	fp=fopen(argv[1],"rb");
	if(!fp)
	{
		printf("Error opening input file %s!\n", argv[1]);
		exit(0);
	}
	fread(dminfo,sizeof(dmarg),1,fp);
	if(dminfo->magicnum!=MAGICNUM)
	{
		printf("not a dm file!\n");
		exit(0);
	}
	if(dminfo->delta<0x10000)
		printf("DM delta value %d\n",dminfo->delta);
	else
	{
		int deltal=dminfo->delta&0xffff;
		int deltar=(dminfo->delta-deltal)/0x10000;
		printf("DM delta value %d/%d\n",deltal,deltar);
	}
	if(dminfo->mode==MODE_TYPE1)
		printf("Channel Delta Mode\n");
	if(dminfo->mode==MODE_TYPE2)
		printf("L+R L-R Mode\n");
	fread(wi,sizeof(wavinfo),1,fp);
	printf("Sample rate %dHz, %d bits, %d channels\n",wi->srate,wi->bits,wi->channel);
	printf("Length %d:%d\n",(wi->samples/wi->srate)/60,(wi->samples/wi->srate)%60);

	
	initsound(wi->srate, wi->channel);
	
	snd_pcm_prepare(pcm_handle);
	decodeDM(fp, wi, dminfo, buf, BUFFER_NUM*frames*2*wi->channel);
	snd_pcm_writei (pcm_handle, buf,  BUFFER_NUM*frames);
	snd_pcm_start(pcm_handle);	
	
	while(1)
	{
		df=decodeDM(fp, wi, dminfo, buf, BUFFER_NUM*frames*2*wi->channel);
		wf = snd_pcm_writei (pcm_handle, buf,  df);
		if(df<BUFFER_NUM*frames)
			break;
	}
	snd_pcm_drain(pcm_handle);
	snd_pcm_close(pcm_handle);
	free(buf);
}
예제 #16
0
static void alsa_sig_io(snd_async_handler_t * h)
{
	/* Previous sample */
	static unsigned char ps = 0x80;
	/* Count samples with similar level (to detect pule/space
	   length), 24.8 fp */
	static unsigned sample_count = 0;
	/* Current signal level (dynamically changes) */
	static unsigned signal_level = 0;
	/* Current state (pulse or space) */
	static unsigned signal_state = 0;
	/* Signal maximum and minimum (used for "zero" detection) */
	static unsigned char signal_max = 0x80, signal_min = 0x80;
	/* Non-zero if we're in zero crossing waiting state */
	static char waiting_zerox = 0;
	/* Store sample size, as our sample buffer will represent
	   shorts or chars */
	unsigned char bytes_per_sample = (alsa_hw.format == SND_PCM_FORMAT_S16_LE ? 2 : 1);

	int i, err;
	char buff[READ_BUFFER_SIZE];
	snd_pcm_sframes_t count;

	/* The value to multiply with number of samples to get microseconds
	 * (fixed-point 24.8 bits).
	 */
	unsigned mulconst = 256000000 / alsa_hw.rate;
	/* Maximal number of samples that can be multiplied by mulconst */
	unsigned maxcount = (((PULSE_MASK << 8) | 0xff) / mulconst) << 8;

	/* First of all, check for underrun. This happens, for example, when
	 * the X11 server starts. If we won't, recording will stop forever.
	 */
	snd_pcm_state_t state = snd_pcm_state(alsa_hw.handle);
	switch (state) {
	case SND_PCM_STATE_SUSPENDED:
		while ((err = snd_pcm_resume(alsa_hw.handle)) == -EAGAIN)
			/* wait until the suspend flag is released */
			sleep(1);
		if (err >= 0)
			goto var_reset;
		/* Fallthrough */
	case SND_PCM_STATE_XRUN:
		alsa_error("prepare", snd_pcm_prepare(alsa_hw.handle));
		alsa_error("start", snd_pcm_start(alsa_hw.handle));
var_reset:			/* Reset variables */
		sample_count = 0;
		waiting_zerox = 0;
		signal_level = 0;
		signal_state = 0;
		signal_max = signal_min = 0x80;
		break;
	default:
		/* Stream is okay */
		break;
	}

	/* Read all available data */
	if ((count = snd_pcm_avail_update(alsa_hw.handle)) > 0) {
		if (count > (READ_BUFFER_SIZE / (bytes_per_sample * alsa_hw.num_channels)))
			count = READ_BUFFER_SIZE / (bytes_per_sample * alsa_hw.num_channels);
		count = snd_pcm_readi(alsa_hw.handle, buff, count);

		/*Loop around samples, if stereo we are
		 *only interested in one channel*/
		for (i = 0; i < count; i++) {
			/* cs == current sample */
			unsigned char cs, as, sl, sz, xz;

			if (bytes_per_sample == 2) {
				cs = ((*(short *)
				       &buff[i * bytes_per_sample * alsa_hw.num_channels +
					     bytes_per_sample * alsa_hw.channel]) >> 8);
				cs ^= 0x80;
			} else {
				cs = buff[i];

				/* Convert signed samples to unsigned */
				if (alsa_hw.format == SND_PCM_FORMAT_S8) {
					cs ^= 0x80;
				}
			}

			/* Track signal middle value (it could differ from 0x80) */
			sz = (signal_min + signal_max) / 2;
			if (cs <= sz)
				signal_min = (signal_min * 7 + cs) / 8;
			if (cs >= sz)
				signal_max = (signal_max * 7 + cs) / 8;

			/* Compute the absolute signal deviation from middle */
			as = U8_ABSDIFF(cs, sz);

			/* Integrate incoming signal (auto level adjustment) */
			signal_level = (signal_level * 7 + as) / 8;

			/* Don't let too low signal levels as it makes us sensible to noise */
			sl = signal_level;
			if (sl < 16)
				sl = 16;

			/* Detect crossing current "zero" level */
			xz = ((cs - sz) ^ (ps - sz)) & 0x80;

			/* Don't wait for zero crossing for too long */
			if (waiting_zerox && !xz)
				waiting_zerox--;

			/* Detect significant signal level changes */
			if ((abs(cs - ps) > sl / 2) && xz)
				waiting_zerox = 2;

			/* If we have crossed zero with a substantial level change, go */
			if (waiting_zerox && xz) {
				lirc_t x;

				waiting_zerox = 0;

				if (sample_count >= maxcount) {
					x = PULSE_MASK;
					sample_count = 0;
				} else {
					/**
					 * Try to interpolate the samples and determine where exactly
					 * the zero crossing point was. This is required as the
					 * remote signal frequency is relatively close to our sampling
					 * frequency thus a sampling error of 1 sample can lead to
					 * substantial time differences.
					 *
					 *     slope = (x2 - x1) / (y2 - y1)
					 *     x = x1 + (y - y1) * slope
					 *
					 * where x1=-1, x2=0, y1=ps, y2=cs, y=sz, thus:
					 *
					 *     x = -1 + (y - y1) / (y2 - y1), or
					 * ==> x = (y - y2) / (y2 - y1)
					 *
					 * y2 (cs) cannot be equal to y1 (ps), otherwise we wouldn't
					 * get here.
					 */
					int delta = (((int)sz - (int)cs) << 8) / ((int)cs - (int)ps);
					/* This expression can easily overflow the 'long' value since it
					 * multiplies two 24.8 values (and we get a 24.16 instead).
					 * To avoid this we cast the intermediate value to "long long".
					 */
					x = (((long long)sample_count + delta) * mulconst) >> 16;
					/* The rest of the quantum is on behalf of next pulse. Note that
					 * sample_count can easily be assigned here a negative value (in
					 * the case zero crossing occurs during the next quantum).
					 */
					sample_count = -delta;
				}

				/* Consider impossible pulses with length greater than
				 * 0.02 seconds, thus it is a space (desynchronization).
				 */
				if ((x > 20000) && signal_state) {
					signal_state = 0;
					LOGPRINTF(1, "Pulse/space desynchronization fixed - len %u", x);
				}

				x |= signal_state;

				/* Write the LIRC code to the FIFO */
				write(alsa_hw.fd, &x, sizeof(x));

				signal_state ^= PULSE_BIT;
			}
예제 #17
0
static int _ksnd_pcm_writei1(snd_pcm_substream_t *substream,
							 unsigned long data,
							 snd_pcm_uframes_t size,
							 int srcchannels, transfer_f transfer)
{
	snd_pcm_runtime_t *runtime = substream->runtime;
	snd_pcm_uframes_t xfer = 0;
	snd_pcm_uframes_t offset = 0;
	int err = 0;
	if (size == 0)
		return 0;
	snd_pcm_stream_lock_irq(substream);
	switch (_ksnd_pcm_state(substream))
	{
		case SNDRV_PCM_STATE_PREPARED:
		case SNDRV_PCM_STATE_RUNNING:
		case SNDRV_PCM_STATE_PAUSED:
			break;
		case SNDRV_PCM_STATE_XRUN:
			err = -EPIPE;
			goto _end_unlock;
		case SNDRV_PCM_STATE_SUSPENDED:
			err = -ESTRPIPE;
			goto _end_unlock;
		default:
			err = -EBADFD;
			goto _end_unlock;
	}
	while (size > 0)
	{
		snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
		snd_pcm_uframes_t avail;
		snd_pcm_uframes_t cont;
		avail = _ksnd_pcm_avail_update(substream);
#if defined(__TDT__) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30))
		// attribute xfer_align is not used any more
		/* #warning Do we have to check the values 'size' and 'avail'? */
		if ((avail < runtime->control->avail_min) && (size > avail))
		{
#else
		if (((avail < runtime->control->avail_min && size > avail) ||
				(size >= runtime->xfer_align
				 && avail < runtime->xfer_align)))
		{
#endif
			int res;
			snd_pcm_stream_unlock_irq(substream);
			do
			{
				res = _ksnd_pcm_wait(substream, 10000);
			}
			while (res == 0 &&
					_ksnd_pcm_state(substream) !=
					SNDRV_PCM_STATE_PREPARED
					&& _ksnd_pcm_state(substream) !=
					SNDRV_PCM_STATE_PAUSED);
			snd_pcm_stream_lock_irq(substream);
			if (res == 0) /* timeout */
			{
				if (_ksnd_pcm_state(substream) ==
						SNDRV_PCM_STATE_SUSPENDED)
				{
					err = -ESTRPIPE;
					goto _end_unlock;
				}
				else
				{
					snd_printd("playback write error "
							   "(DMA or IRQ trouble?)\n");
					err = -EIO;
					goto _end_unlock;
				}
			}
			else if (res < 0) /* error */
			{
				err = res;
				goto _end_unlock;
			}
			avail = snd_pcm_playback_avail(runtime);
		}
		if (avail > runtime->min_align)
			avail -= avail % runtime->min_align;
		frames = size > avail ? avail : size;
		cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
		if (frames > cont)
			frames = cont;
		if (snd_BUG_ON(!frames))
		{
			snd_pcm_stream_unlock_irq(substream);
			return -EINVAL;
		}
		appl_ptr = runtime->control->appl_ptr;
		appl_ofs = appl_ptr % runtime->buffer_size;
		snd_pcm_stream_unlock_irq(substream);
		err = transfer(substream, appl_ofs, data, offset, frames, srcchannels);
		snd_pcm_stream_lock_irq(substream);
		if (err < 0)
			goto _end;
		switch (_ksnd_pcm_state(substream))
		{
			case SNDRV_PCM_STATE_XRUN:
				err = -EPIPE;
				goto _end_unlock;
			case SNDRV_PCM_STATE_SUSPENDED:
				err = -ESTRPIPE;
				goto _end_unlock;
			default:
				break;
		}
		appl_ptr += frames;
		if (appl_ptr >= runtime->boundary)
		{
			runtime->control->appl_ptr = 0;
		}
		else
		{
			runtime->control->appl_ptr = appl_ptr;
		}
		if (substream->ops->ack)
			substream->ops->ack(substream);
		offset += frames;
		size -= frames;
		xfer += frames;
		if (_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_PREPARED &&
				snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t) runtime->start_threshold)
		{
			err = snd_pcm_start(substream);
			if (err < 0)
				goto _end_unlock;
		}
	}
_end_unlock:
	snd_pcm_stream_unlock_irq(substream);
_end:
	return xfer > 0 ? (snd_pcm_sframes_t) xfer : err;
}

int ksnd_pcm_writei(ksnd_pcm_t *kpcm,
					int *data, unsigned int size, unsigned int srcchannels)
{
	snd_pcm_substream_t *substream = kpcm->substream;
	snd_pcm_runtime_t *runtime;
	int err;
	transfer_f out_func = 0;
	runtime = substream->runtime;
	if (substream->pcm->card->number == 2)
	{
		out_func = _ksnd_pcm_IEC60958_transfer;
	}
	else
	{
		out_func = _ksnd_pcm_write_transfer;
	}
	if (_ksnd_pcm_state(substream) == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED
			&& runtime->channels > 1)
		return -EINVAL;
	if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
		return -EINVAL;
	if (size == 0)
		return 0;
	do
	{
		err =
			_ksnd_pcm_writei1(substream, (unsigned long)data, size,
							  srcchannels, out_func);
		if (err < 0)
		{
			if (err == -EAGAIN)
			{
				continue;
			}
			if (err == -EPIPE)
			{
				printk("ALSA Aud underrun for hw:%d,%d\n",
					   substream->pcm->card->number,
					   substream->pcm->device);
				if ((err = ksnd_pcm_prepare(kpcm)) < 0)
					return err;
				continue;
			}
			return err;
		}
		else
		{
			data += samples_to_bytes(runtime, err * srcchannels);
			size -= err;
		}
	}
	while (size > 0);
	return 0;
}
예제 #18
0
int alsa_send_dacs(void)
{
    static double timenow;
    double timelast;
    t_sample *fp, *fp1, *fp2;
    int i, j, k, err, iodev, result, ch, resync = 0;;
    int chansintogo, chansouttogo;
    unsigned int transfersize;

    if (alsa_usemmap)
        return (alsamm_send_dacs());

    if (!alsa_nindev && !alsa_noutdev)
        return (SENDDACS_NO);

    chansintogo = STUFF->st_inchannels;
    chansouttogo = STUFF->st_outchannels;
    transfersize = DEFDACBLKSIZE;

    timelast = timenow;
    timenow = sys_getrealtime();

#ifdef DEBUG_ALSA_XFER
    if (timenow - timelast > 0.050)
        post("long wait between calls: %d",
            (int)(1000 * (timenow - timelast))), fflush(stderr);
    callno++;
#endif


    for (iodev = 0; iodev < alsa_nindev; iodev++)
    {
        result = snd_pcm_state(alsa_indev[iodev].a_handle);
        if (result == SND_PCM_STATE_XRUN)
        {
            int res2 = snd_pcm_start(alsa_indev[iodev].a_handle);
            fprintf(stderr, "restart alsa input\n");
            if (res2 < 0)
                fprintf(stderr, "alsa xrun recovery apparently failed\n");
        }
        snd_pcm_status(alsa_indev[iodev].a_handle, alsa_status);
        if (snd_pcm_status_get_avail(alsa_status) < transfersize)
            return (SENDDACS_NO);
    }
    for (iodev = 0; iodev < alsa_noutdev; iodev++)
    {
        result = snd_pcm_state(alsa_outdev[iodev].a_handle);
        if (result == SND_PCM_STATE_XRUN)
        {
            int res2 = snd_pcm_start(alsa_outdev[iodev].a_handle);
            fprintf(stderr, "restart alsa output\n");
            if (res2 < 0)
                fprintf(stderr, "alsa xrun recovery apparently failed\n");
        }
        snd_pcm_status(alsa_outdev[iodev].a_handle, alsa_status);
        if (snd_pcm_status_get_avail(alsa_status) < transfersize)
            return (SENDDACS_NO);
    }

#ifdef DEBUG_ALSA_XFER
    post("xfer %d", transfersize);
#endif
    /* do output */
    for (iodev = 0, fp1 = STUFF->st_soundout, ch = 0;
        iodev < alsa_noutdev; iodev++)
    {
        int thisdevchans = alsa_outdev[iodev].a_channels;
        int chans = (chansouttogo < thisdevchans ? chansouttogo : thisdevchans);
        chansouttogo -= chans;

        if (alsa_outdev[iodev].a_sampwidth == 4)
        {
            for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE)
                for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
                     j += thisdevchans, fp2++)
            {
                float s1 = *fp2 * INT32_MAX;
                ((t_alsa_sample32 *)alsa_snd_buf)[j] = CLIP32(s1);
            }
            for (; i < thisdevchans; i++, ch++)
                for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans)
                    ((t_alsa_sample32 *)alsa_snd_buf)[j] = 0;
        }
        else if (alsa_outdev[iodev].a_sampwidth == 3)
        {
            for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE)
                for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
                     j += thisdevchans, fp2++)
            {
                int s = *fp2 * 8388352.;
                if (s > 8388351)
                    s = 8388351;
                else if (s < -8388351)
                    s = -8388351;
#if BYTE_ORDER == LITTLE_ENDIAN
                ((char *)(alsa_snd_buf))[3*j] = (s & 255);
                ((char *)(alsa_snd_buf))[3*j+1] = ((s>>8) & 255);
                ((char *)(alsa_snd_buf))[3*j+2] = ((s>>16) & 255);
#else
                fprintf(stderr, "big endian 24-bit not supported");
#endif
            }
            for (; i < thisdevchans; i++, ch++)
                for (j = i, k = DEFDACBLKSIZE; k--; j += thisdevchans)
                    ((char *)(alsa_snd_buf))[3*j] =
                    ((char *)(alsa_snd_buf))[3*j+1] =
                    ((char *)(alsa_snd_buf))[3*j+2] = 0;
        }
        else        /* 16 bit samples */
        {
            for (i = 0; i < chans; i++, ch++, fp1 += DEFDACBLKSIZE)
                for (j = ch, k = DEFDACBLKSIZE, fp2 = fp1; k--;
                     j += thisdevchans, fp2++)
            {
                int s = *fp2 * 32767.;
                if (s > 32767)
                    s = 32767;
                else if (s < -32767)
                    s = -32767;
                ((t_alsa_sample16 *)alsa_snd_buf)[j] = s;
            }
            for (; i < thisdevchans; i++, ch++)
                for (j = ch, k = DEFDACBLKSIZE; k--; j += thisdevchans)
                    ((t_alsa_sample16 *)alsa_snd_buf)[j] = 0;
        }
        result = snd_pcm_writei(alsa_outdev[iodev].a_handle, alsa_snd_buf,
            transfersize);

        if (result != (int)transfersize)
        {
    #ifdef DEBUG_ALSA_XFER
            if (result >= 0 || errno == EAGAIN)
                post("ALSA: write returned %d of %d\n",
                        result, transfersize);
            else post("ALSA: write: %s\n",
                         snd_strerror(errno));
    #endif
            sys_log_error(ERR_DATALATE);
            if (result == -EPIPE)
            {
                result = snd_pcm_prepare(alsa_indev[iodev].a_handle);
                if (result < 0)
                    fprintf(stderr, "read reset error %d\n", result);
            }
            else fprintf(stderr, "read other error %d\n", result);
            resync = 1;
        }

        /* zero out the output buffer */
        memset(STUFF->st_soundout, 0, DEFDACBLKSIZE * sizeof(*STUFF->st_soundout) *
               STUFF->st_outchannels);
        if (sys_getrealtime() - timenow > 0.002)
        {
    #ifdef DEBUG_ALSA_XFER
            post("output %d took %d msec\n",
                    callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
    #endif
            timenow = sys_getrealtime();
            sys_log_error(ERR_DACSLEPT);
        }
    }
예제 #19
0
파일: ALSAInput.cpp 프로젝트: KarolS/ssr
void ALSAInput::Init() {

	snd_pcm_hw_params_t *alsa_hw_params = NULL;

	try {

		// allocate parameter structure
		if(snd_pcm_hw_params_malloc(&alsa_hw_params) < 0) {
			throw std::bad_alloc();
		}

		// open PCM device
		if(snd_pcm_open(&m_alsa_pcm, m_device_name.toAscii().constData(), SND_PCM_STREAM_CAPTURE, 0) < 0) {
			Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't open PCM device!"));
			throw ALSAException();
		}
		if(snd_pcm_hw_params_any(m_alsa_pcm, alsa_hw_params) < 0) {
			Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't get PCM hardware parameters!"));
			throw ALSAException();
		}

		// set access type
		if(snd_pcm_hw_params_set_access(m_alsa_pcm, alsa_hw_params, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
			Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't set access type!"));
			throw ALSAException();
		}

		// set sample format
		if(snd_pcm_hw_params_set_format(m_alsa_pcm, alsa_hw_params, SND_PCM_FORMAT_S16_LE) < 0) {
			Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't set sample format!"));
			throw ALSAException();
		}

		// set sample rate
		unsigned int rate = m_sample_rate;
		if(snd_pcm_hw_params_set_rate_near(m_alsa_pcm, alsa_hw_params, &rate, NULL) < 0) {
			Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't set sample rate!"));
			throw ALSAException();
		}
		if(rate != m_sample_rate) {
			Logger::LogWarning("[ALSAInput::Init] " + QObject::tr("Warning: Sample rate %1 is not supported, using %2 instead. "
																  "This could be a problem if the difference is large.")
							   .arg(m_sample_rate).arg(rate));
			//TODO// enable once resampling is ready
			//m_sample_rate = rate;
		}

		// set channel count
		if(snd_pcm_hw_params_set_channels(m_alsa_pcm, alsa_hw_params, m_channels) < 0) {
			Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't set channel count!"));
			throw ALSAException();
		}

		// set period count
		unsigned int periods = m_alsa_periods;
		if(snd_pcm_hw_params_set_periods_near(m_alsa_pcm, alsa_hw_params, &periods, NULL) < 0) {
			Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't set period count!"));
			throw ALSAException();
		}
		if(periods != m_alsa_periods) {
			Logger::LogWarning("[ALSAInput::Init] " + QObject::tr("Warning: Period count %1 is not supported, using %2 instead. "
																  "This is not a problem.")
							   .arg(m_alsa_periods).arg(periods));
			m_alsa_periods = periods;
		}

		// set period size
		snd_pcm_uframes_t period_size = m_alsa_period_size;
		if(snd_pcm_hw_params_set_period_size_near(m_alsa_pcm, alsa_hw_params, &period_size, NULL) < 0) {
			Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't set period size!"));
			throw ALSAException();
		}
		if(period_size != m_alsa_period_size) {
			Logger::LogWarning("[ALSAInput::Init] " + QObject::tr("Warning: Period size %1 is not supported, using %2 instead. "
																  "This is not a problem.")
							   .arg(m_alsa_period_size).arg(period_size));
			m_alsa_period_size = period_size;
		}

		// apply parameters
		if(snd_pcm_hw_params(m_alsa_pcm, alsa_hw_params) < 0) {
			Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't apply PCM hardware parameters!"));
			throw ALSAException();
		}

		// free parameter structure
		snd_pcm_hw_params_free(alsa_hw_params);
		alsa_hw_params = NULL;

	} catch(...) {
		if(alsa_hw_params != NULL) {
			snd_pcm_hw_params_free(alsa_hw_params);
			alsa_hw_params = NULL;
		}
		throw;
	}

	// start PCM device
	if(snd_pcm_start(m_alsa_pcm) < 0) {
		Logger::LogError("[ALSAInput::Init] " + QObject::tr("Error: Can't start PCM device!"));
		throw ALSAException();
	}

	// start input thread
	m_should_stop = false;
	m_error_occurred = false;
	m_thread = std::thread(&ALSAInput::InputThread, this);

}
예제 #20
0
/*----------------------------------------------------------------
 TIesrFA_ALSA_thread

 This function is the thread function that reads audio sample data
 from the audio channel and puts the data into the circular buffers.
 --------------------------------*/
void* TIesrFA_ALSA_thread( void* aArg )
{
    int rtnval;
    int pcmStarted = FALSE;

    /* The argument to the thread is the TIesrFA instance */
    TIesrFA_t * const aTIesrFAInstance = (TIesrFA_t * const) aArg;

    /* TIesrFA_ALSA specific data */
    TIesrFA_ALSA_t * const ALSAData = (TIesrFA_ALSA_t * const) aTIesrFAInstance->impl_data;


    /* Start the capture of audio data by the audio channel.  If it failed to
     start, then set the read_data flag to zero, indicating failure, and 
     the thread will terminate. */
    rtnval = snd_pcm_start( ALSAData->alsa_handle );
    if( rtnval < 0 )
        ALSAData->read_data = FALSE;
    else
        pcmStarted = TRUE;


    /* Notify main thread that TIesrFA thread has attempted to start the PCM.
     Success or failure is set in the read_data value. If failed, then the
     thread will terminate immediately. */
    sem_post( &( ALSAData->start_semaphore ) );

    /* Loop reading sample data until requested to stop */
    while( ALSAData->read_data == TRUE )
    {
        snd_pcm_sframes_t numSamples;

        /* Wait for audio data to become available.  If no data in one second,
         then something bad has happened. */
        rtnval = snd_pcm_wait( ALSAData->alsa_handle, 1000 );
        if( rtnval == 0 )
        {
            /* Timeout indicating some bad failure. */
            continue;
        }

        /* PCM has indicated data is available. Get amount of data available */
        numSamples = snd_pcm_avail_update( ALSAData->alsa_handle );
        if( numSamples < 0 )
        {
            /* Assume buffer overflow condition */
            ALSAData->buffer_overflow = 1;

            /* Try to recover */
            snd_pcm_prepare( ALSAData->alsa_handle );

            continue;
        }


        /* Determine number of samples to read.  Must not exceed buffer size. */
        numSamples = numSamples > ALSAData->read_samples ?
                ALSAData->read_samples : numSamples;

        /* Read the samples from the PCM */
        numSamples = snd_pcm_readi( ALSAData->alsa_handle,
                ALSAData->read_buffer, numSamples );

        /* Transfer samples to circular frame buffers, or handle error on read. */
        if( ALSAData->read_data == TRUE )
        {
            if( numSamples > 0 )
            {
                int numBytesRead = numSamples * ALSAData->sample_size;
                TIesrFA_ALSA_fillframes( aTIesrFAInstance, numBytesRead );
            }

            else if( numSamples == -EPIPE )
            {
                ALSAData->buffer_overflow = 1;
                snd_pcm_prepare( ALSAData->alsa_handle );
                continue;
            }
            else
            {
                /* Some other failure */
                continue;
            }
        }

    }

    /* The flag has been set to stop processing audio data, so terminate the thread */

    if( pcmStarted )
        snd_pcm_drop( ALSAData->alsa_handle );

    return(void*) TIesrFA_ALSAErrNone;
}
예제 #21
0
파일: listen.c 프로젝트: GunioRobot/vstuff
int main(int argc, char *argv[])
{
	int err;
	struct sniffer_state sts;

	sts.pcm_name = strdup("plughw:0,0");
	sts.stream = SND_PCM_STREAM_PLAYBACK;
	sts.format = SND_PCM_FORMAT_A_LAW;
	sts.rate = 8000;
//	sts.exact_rate;
	sts.periods = 2;
	sts.buffer_time = 25000;
	sts.period_time = 12500;

	snd_pcm_hw_params_alloca(&sts.hwparams);

	if (snd_pcm_open(&sts.pcm, sts.pcm_name, sts.stream, 0) < 0) {
		fprintf(stderr, "Error opening PCM device %s\n", sts.pcm_name);
		return(-1);
	}

	if (snd_pcm_hw_params_any(sts.pcm, sts.hwparams) < 0) {
		fprintf(stderr, "Can not configure this PCM device.\n");
		return(-1);
	}

	if (snd_pcm_hw_params_set_access(sts.pcm, sts.hwparams,
			SND_PCM_ACCESS_MMAP_NONINTERLEAVED) < 0) {
		fprintf(stderr, "Error setting access.\n");
		return(-1);
	}

	if (snd_pcm_hw_params_set_format(sts.pcm, sts.hwparams,
			sts.format) < 0) {
		fprintf(stderr, "Error setting format.\n");
		return(-1);
	}

	sts.exact_rate = sts.rate;
	if (snd_pcm_hw_params_set_rate_near(sts.pcm, sts.hwparams,
			&sts.exact_rate, 0) < 0) {
		fprintf(stderr, "Error setting rate.\n");
		return(-1);
	}

printf("rate: %d\n", sts.exact_rate);

	if (sts.rate != sts.exact_rate) {
		fprintf(stderr, "The rate %d Hz is not supported by your hardware.\n"
			"==> Using %d Hz instead.\n", sts.rate, sts.exact_rate);
	}

	if (snd_pcm_hw_params_set_channels(sts.pcm, sts.hwparams, 1) < 0) {
		fprintf(stderr, "Error setting channels.\n");
		return(-1);
	}

	if (snd_pcm_hw_params_set_periods(sts.pcm, sts.hwparams, sts.periods, 0) < 0) {
		fprintf(stderr, "Error setting periods.\n");
		return(-1);
	}

	if (snd_pcm_hw_params_set_buffer_time_near(sts.pcm, sts.hwparams,
			&sts.buffer_time, &sts.dir) < 0) {
		fprintf(stderr, "Error setting buffersize.\n");
		return(-1);
	}

printf("buffer_time set to %d\n", sts.buffer_time);

	err = snd_pcm_hw_params_get_period_size(sts.hwparams, &sts.period_size, &sts.dir);
	if (err < 0) {
		printf("Unable to get period size for playback: %s\n", snd_strerror(err));
		return err;
	}

printf("period_size = %d\n", (int)sts.period_size);

	if (snd_pcm_hw_params(sts.pcm, sts.hwparams) < 0) {
		fprintf(stderr, "Error setting HW params.\n");
		return(-1);
	}

	setvbuf(stdout, (char *)NULL, _IONBF, 0);

	int router_control_fd = open("/dev/visdn/router-control", O_RDWR);
	if (router_control_fd < 0) {
		perror("Unable to open router-control");
		return 1;
	}

	int fd;
	fd = open("/dev/visdn/streamport", O_RDWR);
	if (fd < 0) {
		perror("cannot open /dev/visdn/streamport");
		return 1;
	}

	struct vsp_ctl vsp_ctl;
	if (ioctl(fd, VISDN_SP_GET_NODEID, (caddr_t)&vsp_ctl) < 0) {
		perror("ioctl(VISDN_SP_GET_NODEID)");
		return 1;
	}

	char node_id[80];
	snprintf(node_id, sizeof(node_id), "/sys/%s", vsp_ctl.node_id);

	struct visdn_connect vc;
	memset(&vc, 0, sizeof(vc));
	strncpy(vc.from_endpoint, argv[1],
				sizeof(vc.from_endpoint));
	strncpy(vc.to_endpoint, node_id,
				sizeof(vc.to_endpoint));

printf("Connect: %s => %s\n", vc.from_endpoint, vc.to_endpoint);

	if (ioctl(router_control_fd, VISDN_IOC_CONNECT, (caddr_t) &vc) < 0) {
		perror("ioctl(VISDN_CONNECT, br=>sp)");
		return 1;
	}

	int pipeline_id = vc.pipeline_id;

	memset(&vc, 0, sizeof(vc));
	vc.pipeline_id = pipeline_id;
	if (ioctl(router_control_fd, VISDN_IOC_PIPELINE_OPEN,
						(caddr_t)&vc) < 0) {
		perror("ioctl(VISDN_PIPELINE_OPEN, br=>sp)");
		return 1;
	}

	memset(&vc, 0, sizeof(vc));
	vc.pipeline_id = pipeline_id;
	if (ioctl(router_control_fd, VISDN_IOC_PIPELINE_START,
						(caddr_t)&vc) < 0) {
		perror("ioctl(VISDN_PIPELINE_START, br=>sp)");
		return 1;
	}






	//double phase = 0;
	const snd_pcm_channel_area_t *my_areas;
	snd_pcm_uframes_t offset, frames, size;
	snd_pcm_sframes_t avail, commitres;
	snd_pcm_state_t state;
	int first = 1;

	while (1) {
		state = snd_pcm_state(sts.pcm);

		if (state == SND_PCM_STATE_XRUN) {
			err = xrun_recovery(sts.pcm, -EPIPE);
			if (err < 0) {
				printf("XRUN recovery failed: %s\n", snd_strerror(err));
				return err;
			}
			first = 1;
		} else if (state == SND_PCM_STATE_SUSPENDED) {
			err = xrun_recovery(sts.pcm, -ESTRPIPE);
			if (err < 0) {
				printf("SUSPEND recovery failed: %s\n", snd_strerror(err));
				return err;
			}
		}

		avail = snd_pcm_avail_update(sts.pcm);
		if (avail < 0) {
			err = xrun_recovery(sts.pcm, avail);
			if (err < 0) {
				printf("avail update failed: %s\n", snd_strerror(err));
				return err;
			}
			first = 1;
			continue;
		}

		if (avail < sts.period_size) {
			if (first) {
				first = 0;
				err = snd_pcm_start(sts.pcm);
				if (err < 0) {
					printf("Start error: %s\n", snd_strerror(err));
					exit(EXIT_FAILURE);
				}
			} else {
				err = snd_pcm_wait(sts.pcm, -1);
				if (err < 0) {
					if ((err = xrun_recovery(sts.pcm, err)) < 0) {
						printf("snd_pcm_wait error: %s\n", snd_strerror(err));
						exit(EXIT_FAILURE);
					}
					first = 1;
				}
			}
			continue;
		}

		size = sts.period_size;
		while (size > 0) {
			frames = size;
			err = snd_pcm_mmap_begin(sts.pcm, &my_areas, &offset, &frames);
			if (err < 0) {
				if ((err = xrun_recovery(sts.pcm, err)) < 0) {
					printf("MMAP begin avail error: %s\n", snd_strerror(err));
					exit(EXIT_FAILURE);
				}

				first = 1;
			}

			int r = read(fd, my_areas[0].addr + offset, frames);
			printf("%d %d %d: ", (int)offset, (int)frames, r);

			int i;
			for (i=0; i<r; i++)
				printf("%02x", *(__u8 *)(my_areas[0].addr + i));

			printf("\n");

			commitres = snd_pcm_mmap_commit(sts.pcm, offset, frames);
			if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
				if ((err = xrun_recovery(sts.pcm, commitres >= 0 ? -EPIPE : commitres)) < 0) {
					printf("MMAP commit error: %s\n", snd_strerror(err));
					exit(EXIT_FAILURE);
				}
				first = 1;
			}
			size -= frames;
		}
	}

	return 0;
}
예제 #22
0
파일: audio-alsa.cpp 프로젝트: snorp/moon
bool
AlsaSource::PreparePcm (snd_pcm_sframes_t *avail)
{
	int err = 0;
	bool closed = false;
	snd_pcm_state_t state;
	
	mutex.Lock ();
	if (initialized) {
		state = snd_pcm_state (pcm);
	} else {
		LOG_ALSA ("AlsaSource::PreparePcm (): pcm has been closed.\n");
		closed = true;
	}
	mutex.Unlock ();
			
	if (closed)
		return false;
		
	switch (state) {
	case SND_PCM_STATE_XRUN:
		LOG_ALSA ("AlsaSource::PreparePcm (): SND_PCM_STATE_XRUN.\n");

		if (!XrunRecovery (-EPIPE))
			return false;

		started = false;
		break;
	case SND_PCM_STATE_SUSPENDED:
		if (!XrunRecovery (-ESTRPIPE))
			return false;
		break;
	case SND_PCM_STATE_SETUP:
		if (!XrunRecovery (-EPIPE))
			return false;

		started = false;
		break;
	case SND_PCM_STATE_RUNNING:
		started = true; // We might have gotten started automatically after writing a certain number of samples.
	case SND_PCM_STATE_PREPARED:
		break;
	case SND_PCM_STATE_PAUSED:
	case SND_PCM_STATE_DRAINING:
	default:
		LOG_ALSA ("AlsaSource::PreparePcm (): state: %s (prepare failed)\n", snd_pcm_state_name (state));
		return false;
	}
	
	err = 0;
	mutex.Lock ();
	if (initialized) {
		*avail = snd_pcm_avail_update (pcm);
	} else {
		closed = true;
	}
	mutex.Unlock ();
	
	if (closed)
		return false;

	if (*avail < 0) {
		if (!XrunRecovery (*avail))
			return false;

		started = false;
		return false;
	}

	if ((snd_pcm_uframes_t) *avail < period_size) {
		if (!started) {
			LOG_ALSA ("AlsaSource::PreparePcm (): starting pcm (period size: %li, available: %li)\n", period_size, *avail);

			mutex.Lock ();
			if (initialized) {
				err = snd_pcm_start (pcm);
			} else {
				closed = true;
			}
			mutex.Unlock ();
			
			if (closed)
				return false;

			if (err < 0) {
				LOG_AUDIO ("AlsaPlayer: Could not start pcm: %s\n", snd_strerror (err));
				return false;
			}
			started = true;
		} else {
			return false;
		}
		return false;
	}

	LOG_ALSA ("AlsaSource::PreparePcm (): Prepared, avail: %li, started: %i\n", *avail, (int) started);

	return true;
}
예제 #23
0
파일: listen.c 프로젝트: GunioRobot/vstuff
static void async_direct_callback(snd_async_handler_t *ahandler)
{
	snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
	struct sniffer_state *sns = snd_async_handler_get_callback_private(ahandler);

	const snd_pcm_channel_area_t *my_areas;
	snd_pcm_uframes_t offset, frames, size;
	snd_pcm_sframes_t avail, commitres;
	snd_pcm_state_t state;
	int first = 0, err;

	while (1) {
		state = snd_pcm_state(handle);
		if (state == SND_PCM_STATE_XRUN) {
			err = xrun_recovery(handle, -EPIPE);
			if (err < 0) {
				printf("XRUN recovery failed: %s\n", snd_strerror(err));
				exit(EXIT_FAILURE);
			}

			first = 1;

		} else if (state == SND_PCM_STATE_SUSPENDED) {

			err = xrun_recovery(handle, -ESTRPIPE);

			if (err < 0) {
				printf("SUSPEND recovery failed: %s\n", snd_strerror(err));
				exit(EXIT_FAILURE);
			}
		}

		avail = snd_pcm_avail_update(handle);

		if (avail < 0) {
			err = xrun_recovery(handle, avail);
			if (err < 0) {
				printf("avail update failed: %s\n", snd_strerror(err));
				exit(EXIT_FAILURE);
			}
			first = 1;
			continue;
		}

		if (avail < sns->period_size) {
			if (first) {

				first = 0;

				err = snd_pcm_start(handle);
				if (err < 0) {
					printf("Start error: %s\n", snd_strerror(err));
					exit(EXIT_FAILURE);
				}
			} else {
				break;
			}

			continue;
		}

		size = sns->period_size;
		while (size > 0) {
			frames = size;
			err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
			if (err < 0) {
				if ((err = xrun_recovery(handle, err)) < 0) {
					printf("MMAP begin avail error: %s\n", snd_strerror(err));
					exit(EXIT_FAILURE);
				}
				first = 1;
			}

	printf("Callback %d %d\n", (int)offset, (int)frames);

			int i;
			for(i=0; i<frames; i++)
				*(__u8 *)(my_areas[0].addr + offset + i)=i%64;

			//generate_sine(my_areas, offset, frames, &sns->phase);

			commitres = snd_pcm_mmap_commit(handle, offset, frames);
			if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
				if ((err = xrun_recovery(handle, commitres >= 0 ? -EPIPE : commitres)) < 0) {
					printf("MMAP commit error: %s\n", snd_strerror(err));
					exit(EXIT_FAILURE);
				}
				first = 1;
			}
			size -= frames;
		}
	}
}
예제 #24
0
파일: alsa.c 프로젝트: igordertigor/xwax
static int handle(struct device *dv)
{
    int r;
    unsigned short revents;
    struct alsa *alsa = (struct alsa*)dv->local;

    /* Check input buffer for timecode capture */
    
    r = pcm_revents(&alsa->capture, &revents);
    if (r < 0)
        return -1;
    
    if (revents & POLLIN) {
        r = capture(dv);
        
        if (r < 0) {
            if (r == -EPIPE) {
                fputs("ALSA: capture xrun.\n", stderr);

                r = snd_pcm_prepare(alsa->capture.pcm);
                if (r < 0) {
                    alsa_error("prepare", r);
                    return -1;
                }

                r = snd_pcm_start(alsa->capture.pcm);
                if (r < 0) {
                    alsa_error("start", r);
                    return -1;
                }

            } else {
                alsa_error("capture", r);
                return -1;
            }
        } 
    }
    
    /* Check the output buffer for playback */
    
    r = pcm_revents(&alsa->playback, &revents);
    if (r < 0)
        return -1;
    
    if (revents & POLLOUT) {
        r = playback(dv);
        
        if (r < 0) {
            if (r == -EPIPE) {
                fputs("ALSA: playback xrun.\n", stderr);
                
                r = snd_pcm_prepare(alsa->playback.pcm);
                if (r < 0) {
                    alsa_error("prepare", r);
                    return -1;
                }

                /* The device starts when data is written. POLLOUT
                 * events are generated in prepared state. */

            } else {
                alsa_error("playback", r);
                return -1;
            }
        }
    }

    return 0;
}
예제 #25
0
void AudioDriver_ALSA::async_direct_callback(snd_async_handler_t *ahandler)
{
	snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler);
	AudioDriver_ALSA* audioDriver = (AudioDriver_ALSA*) snd_async_handler_get_callback_private(ahandler);
	const snd_pcm_channel_area_t *my_areas;
	snd_pcm_uframes_t offset, frames, size;
	snd_pcm_sframes_t avail, commitres;
	snd_pcm_state_t state;
	int first = 0, err;

	while (1) {
		state = snd_pcm_state(handle);
		if (state == SND_PCM_STATE_XRUN) {
			err = snd_pcm_recover(handle, -EPIPE, 0);
			if (err < 0) {
				fprintf(stderr, "ALSA: XRUN recovery failed: %s\n", snd_strerror(err));
			}
			first = 1;
		} else if (state == SND_PCM_STATE_SUSPENDED) {
			err = snd_pcm_recover(handle, ESTRPIPE, 0);
			if (err < 0) {
				fprintf(stderr, "ALSA: SUSPEND recovery failed: %s\n", snd_strerror(err));
			}
		}
		avail = snd_pcm_avail_update(handle);
		if (avail < 0) {
			err = snd_pcm_recover(handle, avail, 0);
			if (err < 0) {
				fprintf(stderr, "ALSA: avail update failed: %s\n", snd_strerror(err));
			}
			first = 1;
			continue;
		}
		if (avail < audioDriver->period_size) {
			if (first) {
				first = 0;
				err = snd_pcm_start(handle);
				if (err < 0) {
					fprintf(stderr, "ALSA: Start error: %s\n", snd_strerror(err));
				}
			} else {
				break;
			}
			continue;
		}

		frames = audioDriver->period_size;
		err = snd_pcm_mmap_begin(handle, &my_areas, &offset, &frames);
		if (err < 0) {
			if ((err = snd_pcm_recover(handle, err, 0)) < 0) {
				fprintf(stderr, "ALSA: MMAP begin avail error: %s\n", snd_strerror(err));
			}
			first = 1;
		}

		if(frames != audioDriver->period_size)
			fprintf(stderr, "ALSA: Invalid buffer size: %lu (should be %lu), skipping..\n", frames, audioDriver->period_size);
			// Certain audio drivers will periodically request buffers of less than one period when
			// soft-resampling (ie, not running at native frequency).  Milkytracker can't handle this,
			// and bad things happen - so best to warn the user and not process.
			// PS - I've disabled soft-resampling for now (see below) so this shouldn't happen.
			// PPS - The downside is that if the user has the wrong mixer rate, they will get an error
			//       dialog - hopefully they'll read the message on stderr...
		else
			audioDriver->fillAudioWithCompensation(static_cast<char*> (my_areas->addr) + offset*4, frames * 2);

		commitres = snd_pcm_mmap_commit(handle, offset, frames);
		if (commitres < 0 || (snd_pcm_uframes_t)commitres != frames) {
			if ((err = snd_pcm_recover(handle, commitres >= 0 ? -EPIPE : commitres, 0)) < 0) {
				fprintf(stderr, "ALSA: MMAP commit error: %s\n", snd_strerror(err));
				// What now?
//				exit(1);
			}
			first = 1;
		}
	}
}
bool QAudioInputPrivate::open()
{
#ifdef DEBUG_AUDIO
    QTime now(QTime::currentTime());
    qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
#endif
    clockStamp.restart();
    timeStamp.restart();
    elapsedTimeOffset = 0;

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

    if (!settings.isValid()) {
        qWarning("QAudioOutput: open error, invalid format.");
    } else if (settings.sampleRate() <= 0) {
        qWarning("QAudioOutput: open error, invalid sample rate (%d).",
                 settings.sampleRate());
    } else {
        err = -1;
    }

    if (err == 0) {
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        emit errorChanged(errorState);
        return false;
    }


    QString dev = QString(QLatin1String(m_device.constData()));
    QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioInput);
    if(dev.compare(QLatin1String("default")) == 0) {
#if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
        if (devices.size() > 0)
            dev = QLatin1String(devices.first());
        else
            return false;
#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_CAPTURE,0);
        if(err < 0)
            count++;
    }
    if (( err < 0)||(handle == 0)) {
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        emit stateChanged(deviceState);
        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("QAudioInput: 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("QAudioInput: 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("QAudioInput: snd_pcm_hw_params_set_access: err = %1").arg(err);
        }
    }
    if ( !fatal ) {
        err = setFormat();
        if ( err < 0 ) {
            fatal = true;
            errMessage = QString::fromLatin1("QAudioInput: 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("QAudioInput: 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("QAudioInput: 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("QAudioInput: 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("QAudioInput: 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("QAudioInput: 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("QAudioInput: snd_pcm_hw_params: err = %1").arg(err);
        }
    }
    if( err < 0) {
        qWarning()<<errMessage;
        errorState = QAudio::OpenError;
        deviceState = QAudio::StoppedState;
        emit stateChanged(deviceState);
        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[buffer_size];
    snd_pcm_prepare( handle );
    snd_pcm_start(handle);

    // Step 5: Setup timer
    bytesAvailable = checkBytesReady();

    if(pullMode)
        connect(audioSource,SIGNAL(readyRead()),this,SLOT(userFeed()));

    // Step 6: Start audio processing
    chunks = buffer_size/period_size;
    timer->start(period_time*chunks/2000);

    errorState  = QAudio::NoError;

    totalTimeValue = 0;

    return true;
}
예제 #27
0
void CALSAAudioSource::ProcessAudio(void)
{
	int err;
	
  if (m_audioSrcFrameNumber == 0) {
  	// Start the device
    if ((err = snd_pcm_start(m_pcmHandle)) < 0) {
      error_message("Couldn't start the PCM device: %s", snd_strerror(err));
    }
  }
	
  snd_pcm_status_t *status;
  snd_pcm_status_alloca(&status);

  // for efficiency, process 1 second before returning to check for commands
  for (int pass = 0; pass < m_maxPasses && m_stop_thread == false; pass++) {

    u_int8_t*     pcmFrameBuffer;
    pcmFrameBuffer = (u_int8_t*)malloc(m_pcmFrameSize);

    // The alsa frames is not the same as the pcm frames used to feed the encoder
    // Calculate how many alsa frames is neccesary to read to fill one pcm frame
	  snd_pcm_uframes_t num_frames = m_pcmFrameSize / (m_audioSrcChannels * sizeof(u_int16_t));
	  
		// Check how many bytes there is to read in the buffer, it will be used to calculate timestamp
    snd_pcm_status(m_pcmHandle, status);
		unsigned long avail_bytes = snd_pcm_status_get_avail(status) * (m_audioSrcChannels * sizeof(u_int16_t));
    Timestamp currentTime = GetTimestamp();
    Timestamp timestamp;

    // Read num_frames frames from the PCM device
    // pointed to by pcm_handle to buffer capdata.
    // Returns the number of frames actually read.
    // TODO On certain alsa configurations, e.g. when using dsnoop with low sample rate, the period gets too small. What to do about that?
    snd_pcm_sframes_t framesRead;
    if((framesRead = snd_pcm_readi(m_pcmHandle, pcmFrameBuffer, num_frames)) == -EPIPE) {
      snd_pcm_prepare(m_pcmHandle);
      // Buffer Overrun. This means the audio buffer is full, and not capturing
      // we want to make the timestamp based on the previous one
      // When we hit this case, we start using the m_timestampOverflowArray
      // This will give us a timestamp for when the array is full.
      // 
      // In other words, if we have a full audio buffer (ie: it's not loading
      // any more), we start storing the current timestamp into the array.
      // This will let us "catch up", and have a somewhat accurate timestamp
      // when we loop around
      // 
      // wmay - I'm not convinced that this actually works - if the buffer
      // cleans up, we'll ignore m_timestampOverflowArray
      if (m_timestampOverflowArray != NULL && m_timestampOverflowArray[m_timestampOverflowArrayIndex] != 0) {
        timestamp = m_timestampOverflowArray[m_timestampOverflowArrayIndex];
      } else {
        timestamp = m_prevTimestamp + SrcSamplesToTicks(avail_bytes);
      }

      if (m_timestampOverflowArray != NULL)
        m_timestampOverflowArray[m_timestampOverflowArrayIndex] = currentTime;

      debug_message("audio buffer full !");
    } else {
      if (framesRead < (snd_pcm_sframes_t) num_frames) {
        error_message("Bad audio read. Expected %li frames, got %li", num_frames, framesRead);
        free(pcmFrameBuffer);
        continue;
      }

      // buffer is not full - so, we make the timestamp based on the number
      // of bytes in the buffer that we read.
      timestamp = currentTime - SrcSamplesToTicks(SrcBytesToSamples(avail_bytes));
      if (m_timestampOverflowArray != NULL)
        m_timestampOverflowArray[m_timestampOverflowArrayIndex] = 0;
    }
    //debug_message("alsa read");
#ifdef DEBUG_TIMESTAMPS
    debug_message("avail_bytes=%lu t="U64" timestamp="U64" delta="U64,
                  avail_bytes, currentTime, timestamp, timestamp - m_prevTimestamp);
#endif

    m_prevTimestamp = timestamp;
    if (m_timestampOverflowArray != NULL) {
      m_timestampOverflowArrayIndex = (m_timestampOverflowArrayIndex + 1) % m_audioMaxBufferFrames;
    }
#ifdef DEBUG_TIMESTAMPS
    debug_message("pcm forward "U64" %u", timestamp, m_pcmFrameSize);
#endif
    if (m_audioSrcFrameNumber == 0 && m_videoSource != NULL) {
      m_videoSource->RequestKeyFrame(timestamp);
    }
    m_audioSrcFrameNumber++;
    CMediaFrame *frame = new CMediaFrame(PCMAUDIOFRAME,
					 pcmFrameBuffer, 
					 m_pcmFrameSize, 
					 timestamp);
    ForwardFrame(frame);
  }
}
예제 #28
0
int main(int argc, char *argv[])
{
	struct option long_option[] =
	{
		{"help", 0, NULL, 'h'},
		{"pdevice", 1, NULL, 'P'},
		{"cdevice", 1, NULL, 'C'},
		{"min", 1, NULL, 'm'},
		{"max", 1, NULL, 'M'},
		{"frames", 1, NULL, 'F'},
		{"format", 1, NULL, 'f'},
		{"channels", 1, NULL, 'c'},
		{"rate", 1, NULL, 'r'},
		{"seconds", 1, NULL, 's'},
		{"block", 0, NULL, 'b'},
		{"time", 1, NULL, 't'},
		{"poll", 0, NULL, 'p'},
		{"effect", 0, NULL, 'e'},
		{NULL, 0, NULL, 0},
	};
	snd_pcm_t *phandle, *chandle;
	char *buffer;
	int err, latency, morehelp;
	int ok;
	snd_timestamp_t p_tstamp, c_tstamp;
	ssize_t r;
	size_t frames_in, frames_out, in_max;
	int effect = 0;
	morehelp = 0;
	while (1) {
		int c;
		if ((c = getopt_long(argc, argv, "hP:C:m:M:F:f:c:r:s:bt:pe", long_option, NULL)) < 0)
			break;
		switch (c) {
		case 'h':
			morehelp++;
			break;
		case 'P':
			pdevice = strdup(optarg);
			break;
		case 'C':
			cdevice = strdup(optarg);
			break;
		case 'm':
			err = atoi(optarg) / 2;
			latency_min = err >= 4 ? err : 4;
			if (latency_max < latency_min)
				latency_max = latency_min;
			break;
		case 'M':
			err = atoi(optarg) / 2;
			latency_max = latency_min > err ? latency_min : err;
			break;
		case 'f':
			format = snd_pcm_format_value(optarg);
			if (format == SND_PCM_FORMAT_UNKNOWN) {
				printf("Unknown format, setting to default S16_LE\n");
				format = SND_PCM_FORMAT_S16_LE;
			}
			break;
		case 'c':
			err = atoi(optarg);
			channels = err >= 1 && err < 1024 ? err : 1;
			break;
		case 'r':
			err = atoi(optarg);
			rate = err >= 4000 && err < 200000 ? err : 44100;
			break;
		case 's':
			err = atoi(optarg);
			loop_sec = err >= 1 && err <= 100000 ? err : 30;
			break;
		case 'b':
			block = 1;
			break;
		case 't':
			tick_time = atoi(optarg);
			tick_time = tick_time < 0 ? 0 : tick_time;
			break;
		case 'p':
			use_poll = 1;
			break;
		case 'e':
			effect = 1;
			break;
		}
	}

	if (morehelp) {
		help();
		return 0;
	}
	err = snd_output_stdio_attach(&output, stdout, 0);
	if (err < 0) {
		printf("Output failed: %s\n", snd_strerror(err));
		return 0;
	}

	loop_limit = loop_sec * rate;
	latency = latency_min - 4;
	buffer = malloc((latency_max * snd_pcm_format_width(format) / 8) * 2);

	setscheduler();

	printf("Playback device is %s\n", pdevice);
	printf("Capture device is %s\n", cdevice);
	printf("Parameters are %iHz, %s, %i channels, %s mode\n", rate, snd_pcm_format_name(format), channels, block ? "blocking" : "non-blocking");
	printf("Wanted tick time: %ius, poll mode: %s\n", tick_time, use_poll ? "yes" : "no");
	printf("Loop limit is %li frames, minimum latency = %i, maximum latency = %i\n", loop_limit, latency_min * 2, latency_max * 2);

	if ((err = snd_pcm_open(&phandle, pdevice, SND_PCM_STREAM_PLAYBACK, block ? 0 : SND_PCM_NONBLOCK)) < 0) {
		printf("Playback open error: %s\n", snd_strerror(err));
		return 0;
	}
	if ((err = snd_pcm_open(&chandle, cdevice, SND_PCM_STREAM_CAPTURE, block ? 0 : SND_PCM_NONBLOCK)) < 0) {
		printf("Record open error: %s\n", snd_strerror(err));
		return 0;
	}

	/* initialize the filter sweep variables */
	if (effect) {
		fs = (float) rate;
		BW = FILTER_BANDWIDTH;

		lfo = 0;
		dlfo = 2.*M_PI*FILTERSWEEP_LFO_FREQ/fs;

		x[0] = (float*) malloc(channels*sizeof(float));		
		x[1] = (float*) malloc(channels*sizeof(float));		
		x[2] = (float*) malloc(channels*sizeof(float));		
		y[0] = (float*) malloc(channels*sizeof(float));		
		y[1] = (float*) malloc(channels*sizeof(float));		
		y[2] = (float*) malloc(channels*sizeof(float));		
	}
			  
	while (1) {
		frames_in = frames_out = 0;
		if (setparams(phandle, chandle, &latency) < 0)
			break;
		showlatency(latency);
		if (tick_time_ok)
			printf("Using tick time %ius\n", tick_time_ok);
		if ((err = snd_pcm_link(chandle, phandle)) < 0) {
			printf("Streams link error: %s\n", snd_strerror(err));
			exit(0);
		}
		if (snd_pcm_format_set_silence(format, buffer, latency*channels) < 0) {
			fprintf(stderr, "silence error\n");
			break;
		}
		if (writebuf(phandle, buffer, latency, &frames_out) < 0) {
			fprintf(stderr, "write error\n");
			break;
		}
		if (writebuf(phandle, buffer, latency, &frames_out) < 0) {
			fprintf(stderr, "write error\n");
			break;
		}

		if ((err = snd_pcm_start(chandle)) < 0) {
			printf("Go error: %s\n", snd_strerror(err));
			exit(0);
		}
		gettimestamp(phandle, &p_tstamp);
		gettimestamp(chandle, &c_tstamp);
#if 0
		printf("Playback:\n");
		showstat(phandle, frames_out);
		printf("Capture:\n");
		showstat(chandle, frames_in);
#endif

		ok = 1;
		in_max = 0;
		while (ok && frames_in < loop_limit) {
			if (use_poll) {
				/* use poll to wait for next event */
				snd_pcm_wait(chandle, 1000);
			}
			if ((r = readbuf(chandle, buffer, latency, &frames_in, &in_max)) < 0)
				ok = 0;
			else {
				if (effect)
					applyeffect(buffer,r);
			 	if (writebuf(phandle, buffer, r, &frames_out) < 0)
					ok = 0;
			}
		}
		if (ok)
			printf("Success\n");
		else
			printf("Failure\n");
		printf("Playback:\n");
		showstat(phandle, frames_out);
		printf("Capture:\n");
		showstat(chandle, frames_in);
		showinmax(in_max);
		if (p_tstamp.tv_sec == p_tstamp.tv_sec &&
		    p_tstamp.tv_usec == c_tstamp.tv_usec)
			printf("Hardware sync\n");
		snd_pcm_drop(chandle);
		snd_pcm_nonblock(phandle, 0);
		snd_pcm_drain(phandle);
		snd_pcm_nonblock(phandle, !block ? 1 : 0);
		if (ok) {
#if 1
			printf("Playback time = %li.%i, Record time = %li.%i, diff = %li\n",
			       p_tstamp.tv_sec,
			       (int)p_tstamp.tv_usec,
			       c_tstamp.tv_sec,
			       (int)c_tstamp.tv_usec,
			       timediff(p_tstamp, c_tstamp));
#endif
			break;
		}
		snd_pcm_unlink(chandle);
		snd_pcm_hw_free(phandle);
		snd_pcm_hw_free(chandle);
	}
	snd_pcm_close(phandle);
	snd_pcm_close(chandle);
	return 0;
}
예제 #29
0
파일: alsa.c 프로젝트: 9heart/DT3
static ALuint ALSAProc(ALvoid *ptr)
{
    ALCdevice *pDevice = (ALCdevice*)ptr;
    alsa_data *data = (alsa_data*)pDevice->ExtraData;
    const snd_pcm_channel_area_t *areas = NULL;
    snd_pcm_uframes_t update_size, num_updates;
    snd_pcm_sframes_t avail, commitres;
    snd_pcm_uframes_t offset, frames;
    char *WritePtr;
    int err;

    SetRTPriority();

    update_size = pDevice->UpdateSize;
    num_updates = pDevice->NumUpdates;
    while(!data->killNow)
    {
        int state = verify_state(data->pcmHandle);
        if(state < 0)
        {
            ERR("Invalid state detected: %s\n", snd_strerror(state));
            aluHandleDisconnect(pDevice);
            break;
        }

        avail = snd_pcm_avail_update(data->pcmHandle);
        if(avail < 0)
        {
            ERR("available update failed: %s\n", snd_strerror(avail));
            continue;
        }

        if((snd_pcm_uframes_t)avail > update_size*(num_updates+1))
        {
            WARN("available samples exceeds the buffer size\n");
            snd_pcm_reset(data->pcmHandle);
            continue;
        }

        // make sure there's frames to process
        if((snd_pcm_uframes_t)avail < update_size)
        {
            if(state != SND_PCM_STATE_RUNNING)
            {
                err = snd_pcm_start(data->pcmHandle);
                if(err < 0)
                {
                    ERR("start failed: %s\n", snd_strerror(err));
                    continue;
                }
            }
            if(snd_pcm_wait(data->pcmHandle, 1000) == 0)
                ERR("Wait timeout... buffer size too low?\n");
            continue;
        }
        avail -= avail%update_size;

        // it is possible that contiguous areas are smaller, thus we use a loop
        while(avail > 0)
        {
            frames = avail;

            err = snd_pcm_mmap_begin(data->pcmHandle, &areas, &offset, &frames);
            if(err < 0)
            {
                ERR("mmap begin error: %s\n", snd_strerror(err));
                break;
            }

            WritePtr = (char*)areas->addr + (offset * areas->step / 8);
            aluMixData(pDevice, WritePtr, frames);

            commitres = snd_pcm_mmap_commit(data->pcmHandle, offset, frames);
            if(commitres < 0 || (commitres-frames) != 0)
            {
                ERR("mmap commit error: %s\n",
                    snd_strerror(commitres >= 0 ? -EPIPE : commitres));
                break;
            }

            avail -= frames;
        }
    }

    return 0;
}