Example #1
0
static ALCuint pulse_available_samples(ALCdevice *device) //{{{
{
    pulse_data *data = device->ExtraData;
    size_t samples;

    pa_threaded_mainloop_lock(data->loop);
    /* Capture is done in fragment-sized chunks, so we loop until we get all
     * that's available */
    samples = (device->Connected ? pa_stream_readable_size(data->stream) : 0);
    while(samples > 0)
    {
        const void *buf;
        size_t length;

        if(pa_stream_peek(data->stream, &buf, &length) < 0)
        {
            ERR("pa_stream_peek() failed: %s\n",
                pa_strerror(pa_context_errno(data->context)));
            break;
        }

        WriteRingBuffer(data->ring, buf, length/data->frame_size);
        samples -= length;

        pa_stream_drop(data->stream);
    }
    pa_threaded_mainloop_unlock(data->loop);

    return RingBufferSize(data->ring);
} //}}}
int QPulseAudioInput::checkBytesReady()
{
    if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState) {
        m_bytesAvailable = 0;
    } else {
        m_bytesAvailable = pa_stream_readable_size(m_stream);
    }

    return m_bytesAvailable;
}
static void stream_read_cb(pa_stream *p, size_t nbytes, void *userdata) {
    /* We don't care about the data, just drop it */

    for (;;) {
        const void *data;

        pa_assert_se((nbytes = pa_stream_readable_size(p)) != (size_t) -1);

        if (nbytes <= 0)
            break;

        fail_unless(pa_stream_peek(p, &data, &nbytes) == 0);
        fail_unless(pa_stream_drop(p) == 0);
    }
}
Example #4
0
static
void
deh_stream_first_readwrite_callback(pa_mainloop_api *api, pa_defer_event *de, void *userdata)
{
    pa_stream *s = userdata;

    if (s->direction == PA_STREAM_PLAYBACK) {
        size_t writable_size = pa_stream_writable_size(s);
        if (s->write_cb && writable_size > 0)
            s->write_cb(s, writable_size, s->write_cb_userdata);
    } else if (s->direction == PA_STREAM_RECORD) {
        size_t readable_size = pa_stream_readable_size(s);
        if (s->read_cb && readable_size > 0)
            s->read_cb(s, readable_size, s->read_cb_userdata);
    }
    pa_stream_unref(s);
}
Example #5
0
static ALCuint pulse_available_samples(ALCdevice *device)
{
    pulse_data *data = device->ExtraData;
    size_t readable = data->cap_remain;

    if(device->Connected)
    {
        ssize_t got = pa_stream_readable_size(data->stream);
        if(got < 0)
        {
            ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got));
            aluHandleDisconnect(device);
        }
        else if((size_t)got > data->cap_len)
            readable += got - data->cap_len;
    }

    if(data->last_readable < readable)
        data->last_readable = readable;
    return data->last_readable / pa_frame_size(&data->spec);
}
Example #6
0
/* This is called whenever new data may is available */
static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {

    pa_assert(s);
    pa_assert(length > 0);

    if (raw) {
        pa_assert(!sndfile);

        if (stdio_event)
            mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);

        while (pa_stream_readable_size(s) > 0) {
            const void *data;

            if (pa_stream_peek(s, &data, &length) < 0) {
                pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
                quit(1);
                return;
            }

            pa_assert(data);
            pa_assert(length > 0);

            if (buffer) {
                buffer = pa_xrealloc(buffer, buffer_length + length);
                memcpy((uint8_t*) buffer + buffer_length, data, length);
                buffer_length += length;
            } else {
                buffer = pa_xmalloc(length);
                memcpy(buffer, data, length);
                buffer_length = length;
                buffer_index = 0;
            }

            pa_stream_drop(s);
        }

    } else {
        pa_assert(sndfile);

        while (pa_stream_readable_size(s) > 0) {
            sf_count_t bytes;
            const void *data;

            if (pa_stream_peek(s, &data, &length) < 0) {
                pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
                quit(1);
                return;
            }

            pa_assert(data);
            pa_assert(length > 0);

            if (writef_function) {
                size_t k = pa_frame_size(&sample_spec);

                if ((bytes = writef_function(sndfile, data, (sf_count_t) (length/k))) > 0)
                    bytes *= (sf_count_t) k;

            } else
                bytes = sf_write_raw(sndfile, data, (sf_count_t) length);

            if (bytes < (sf_count_t) length)
                quit(1);

            pa_stream_drop(s);
        }
    }
}
Example #7
0
/* This is called whenever new data may is available */
static void stream_read_callback(pa_stream *s, size_t length, void *userdata) {

    pa_assert(s);
    pa_assert(length > 0);

    if (raw) {
        pa_assert(!sndfile);

        if (stdio_event)
            mainloop_api->io_enable(stdio_event, PA_IO_EVENT_OUTPUT);

        while (pa_stream_readable_size(s) > 0) {
            const void *data;

            if (pa_stream_peek(s, &data, &length) < 0) {
                pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
                quit(1);
                return;
            }

            pa_assert(length > 0);

            /* If there is a hole in the stream, we generate silence, except
             * if it's a passthrough stream in which case we skip the hole. */
            if (data || !(flags & PA_STREAM_PASSTHROUGH)) {
                buffer = pa_xrealloc(buffer, buffer_length + length);
                if (data)
                    memcpy((uint8_t *) buffer + buffer_length, data, length);
                else
                    pa_silence_memory((uint8_t *) buffer + buffer_length, length, &sample_spec);

                buffer_length += length;
            }

            pa_stream_drop(s);
        }

    } else {
        pa_assert(sndfile);

        while (pa_stream_readable_size(s) > 0) {
            sf_count_t bytes;
            const void *data;

            if (pa_stream_peek(s, &data, &length) < 0) {
                pa_log(_("pa_stream_peek() failed: %s"), pa_strerror(pa_context_errno(context)));
                quit(1);
                return;
            }

            pa_assert(length > 0);

            if (!data && (flags & PA_STREAM_PASSTHROUGH)) {
                pa_stream_drop(s);
                continue;
            }

            if (!data && length > silence_buffer_length) {
                silence_buffer = pa_xrealloc(silence_buffer, length);
                pa_silence_memory((uint8_t *) silence_buffer + silence_buffer_length, length - silence_buffer_length, &sample_spec);
                silence_buffer_length = length;
            }

            if (writef_function) {
                size_t k = pa_frame_size(&sample_spec);

                if ((bytes = writef_function(sndfile, data ? data : silence_buffer, (sf_count_t) (length/k))) > 0)
                    bytes *= (sf_count_t) k;

            } else
                bytes = sf_write_raw(sndfile, data ? data : silence_buffer, (sf_count_t) length);

            if (bytes < (sf_count_t) length)
                quit(1);

            pa_stream_drop(s);
        }
    }
}
Example #8
0
/*
 * audio record callback
 * args:
 *   s - pointer to pa_stream
 *   length - buffer length
 *   data - pointer to user data
 *
 * asserts:
 *   none
 *
 * returns: none
 */
static void stream_request_cb(pa_stream *s, size_t length, void *data)
{

    audio_context_t *audio_ctx = (audio_context_t *) data;

	if(audio_ctx->channels == 0)
	{
		fprintf(stderr, "AUDIO: (pulseaudio) stream_request_cb failed: channels = 0\n");
		return;
	}
	
	if(audio_ctx->samprate == 0)
	{
		fprintf(stderr, "AUDIO: (pulseaudio) stream_request_cb failed: samprate = 0\n");
		return;
	}
	
	uint64_t frame_length = NSEC_PER_SEC / audio_ctx->samprate; /*in nanosec*/
	int64_t ts = 0;
	int64_t buff_ts = 0;
	uint32_t i = 0;

	while (pa_stream_readable_size(s) > 0)
	{
		const void *inputBuffer;
		size_t length;

		/*read from stream*/
		if (pa_stream_peek(s, &inputBuffer, &length) < 0)
		{
			fprintf(stderr, "AUDIO: (pulseaudio) pa_stream_peek() failed\n");
			return;
		}

		if(length == 0)
		{
			fprintf(stderr, "AUDIO: (pulseaudio) empty buffer!\n");
			return; /*buffer is empty*/
		}

		get_latency(s);

		ts = ns_time_monotonic() - (latency * 1000);

		if(audio_ctx->last_ts <= 0)
			audio_ctx->last_ts = ts;


		uint32_t numSamples = (uint32_t) length / sizeof(sample_t);

		const sample_t *rptr = (const sample_t*) inputBuffer;
		sample_t *capture_buff = (sample_t *) audio_ctx->capture_buff;

		int chan = 0;
		/*store capture samples or silence if inputBuffer == NULL (hole)*/
		for( i = 0; i < numSamples; ++i )
		{
			capture_buff[sample_index] = inputBuffer ? *rptr++ : 0;
			sample_index++;

			/*store peak value*/
			if(audio_ctx->capture_buff_level[chan] < capture_buff[sample_index])
				audio_ctx->capture_buff_level[chan] = capture_buff[sample_index];
			chan++;
			if(chan >= audio_ctx->channels)
				chan = 0;

			if(sample_index >= audio_ctx->capture_buff_size)
			{
				buff_ts = ts + ( i / audio_ctx->channels ) * frame_length;

				audio_fill_buffer(audio_ctx, buff_ts);

				/*reset*/
				audio_ctx->capture_buff_level[0] = 0;
				audio_ctx->capture_buff_level[1] = 0;
				sample_index = 0;
			}
		}

		pa_stream_drop(s); /*clean the samples*/
	}

}
JNIEXPORT jint JNICALL
Java_org_jitsi_impl_neomedia_pulseaudio_PA_stream_1readable_1size
    (JNIEnv *env, jclass clazz, jlong s)
{
    return pa_stream_readable_size((pa_stream *) (intptr_t) s);
}
Example #10
0
qint64 QPulseAudioInput::read(char *data, qint64 len)
{
    m_bytesAvailable = checkBytesReady();

    setError(QAudio::NoError);
    setState(QAudio::ActiveState);

    int readBytes = 0;

    if (!m_pullMode && !m_tempBuffer.isEmpty()) {
        readBytes = qMin(static_cast<int>(len), m_tempBuffer.size());
        memcpy(data, m_tempBuffer.constData(), readBytes);
        m_totalTimeValue += readBytes;

        if (readBytes < m_tempBuffer.size()) {
            m_tempBuffer.remove(0, readBytes);
            return readBytes;
        }

        m_tempBuffer.clear();
    }

    while (pa_stream_readable_size(m_stream) > 0) {
        size_t readLength = 0;

#ifdef DEBUG_PULSE
        qDebug() << "QPulseAudioInput::read -- " << pa_stream_readable_size(m_stream) << " bytes available from pulse audio";
#endif

        QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
        pulseEngine->lock();

        const void *audioBuffer;

        // Second and third parameters (audioBuffer and length) to pa_stream_peek are output parameters,
        // the audioBuffer pointer is set to point to the actual pulse audio data,
        // and the length is set to the length of this data.
        if (pa_stream_peek(m_stream, &audioBuffer, &readLength) < 0) {
            qWarning() << QString("pa_stream_peek() failed: %1").arg(pa_strerror(pa_context_errno(pa_stream_get_context(m_stream))));
            pulseEngine->unlock();
            return 0;
        }

        qint64 actualLength = 0;
        if (m_pullMode) {
            QByteArray adjusted(readLength, Qt::Uninitialized);
            applyVolume(audioBuffer, adjusted.data(), readLength);
            actualLength = m_audioSource->write(adjusted);

            if (actualLength < qint64(readLength)) {
                pulseEngine->unlock();

                setError(QAudio::UnderrunError);
                setState(QAudio::IdleState);

                return actualLength;
            }
        } else {
            actualLength = qMin(static_cast<int>(len - readBytes), static_cast<int>(readLength));
            applyVolume(audioBuffer, data + readBytes, actualLength);
        }

#ifdef DEBUG_PULSE
        qDebug() << "QPulseAudioInput::read -- wrote " << actualLength << " to client";
#endif

        if (actualLength < qint64(readLength)) {
#ifdef DEBUG_PULSE
            qDebug() << "QPulseAudioInput::read -- appending " << readLength - actualLength << " bytes of data to temp buffer";
#endif
            int diff = readLength - actualLength;
            int oldSize = m_tempBuffer.size();
            m_tempBuffer.resize(m_tempBuffer.size() + diff);
            applyVolume(static_cast<const char *>(audioBuffer) + actualLength, m_tempBuffer.data() + oldSize, diff);
            QMetaObject::invokeMethod(this, "userFeed", Qt::QueuedConnection);
        }

        m_totalTimeValue += actualLength;
        readBytes += actualLength;

        pa_stream_drop(m_stream);
        pulseEngine->unlock();

        if (!m_pullMode && readBytes >= len)
            break;

        if (m_intervalTime && (m_timeStamp.elapsed() + m_elapsedTimeOffset) > m_intervalTime) {
            emit notify();
            m_elapsedTimeOffset = m_timeStamp.elapsed() + m_elapsedTimeOffset - m_intervalTime;
            m_timeStamp.restart();
        }
    }

#ifdef DEBUG_PULSE
    qDebug() << "QPulseAudioInput::read -- returning after reading " << readBytes << " bytes";
#endif

    return readBytes;
}
Example #11
0
static
void
data_available_for_stream(pa_mainloop_api *a, pa_io_event *ioe, int fd, pa_io_event_flags_t events,
                          void *userdata)
{
    pa_stream          *s = userdata;
    snd_pcm_sframes_t   frame_count;
    size_t              frame_size = pa_frame_size(&s->ss);
    char                buf[16 * 1024];
    int                 paused = g_atomic_int_get(&s->paused);

    if (events & (PA_IO_EVENT_INPUT | PA_IO_EVENT_OUTPUT)) {

#if HAVE_SND_PCM_AVAIL
        frame_count = snd_pcm_avail(s->ph);
#else
        snd_pcm_hwsync(s->ph);
        frame_count = snd_pcm_avail_update(s->ph);
#endif

        if (frame_count < 0) {
            if (frame_count == -EBADFD) {
                // stream was closed
                return;
            }

            int cnt = 0, ret;
            do {
                cnt ++;
                ret = snd_pcm_recover(s->ph, frame_count, 1);
            } while (ret == -1 && errno == EINTR && cnt < 5);

#if HAVE_SND_PCM_AVAIL
            frame_count = snd_pcm_avail(s->ph);
#else
            snd_pcm_hwsync(s->ph);
            frame_count = snd_pcm_avail_update(s->ph);
#endif

            if (frame_count < 0) {
                trace_error("%s, can't recover after failed snd_pcm_avail (%d)\n", __func__,
                            (int)frame_count);
                return;
            }
        }
    } else {
        return;
    }

    if (events & PA_IO_EVENT_OUTPUT) {
        if (paused) {
            // client stream is corked. Pass silence to ALSA
            size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size);
            memset(buf, 0, bytecnt);
            snd_pcm_writei(s->ph, buf, bytecnt / frame_size);
        } else {
            size_t writable_size = pa_stream_writable_size(s);

            if (s->write_cb && writable_size > 0)
                s->write_cb(s, writable_size, s->write_cb_userdata);

            size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size);
            bytecnt = ringbuffer_read(s->rb, buf, bytecnt);

            if (bytecnt == 0) {
                // application is not ready yet, play silence
                bytecnt = MIN(sizeof(buf), frame_count * frame_size);
                memset(buf, 0, bytecnt);
            }
            snd_pcm_writei(s->ph, buf, bytecnt / frame_size);
        }
    }

    if (events & PA_IO_EVENT_INPUT) {
        if (paused) {
            // client stream is corked. Read data from ALSA and discard them
            size_t bytecnt = MIN(sizeof(buf), frame_count * frame_size);
            snd_pcm_readi(s->ph, buf, bytecnt / frame_size);
        } else {
            size_t bytecnt = ringbuffer_writable_size(s->rb);

            if (bytecnt == 0) {
                // ringbuffer is full because app doesn't read data fast enough.
                // Make some room
                ringbuffer_drop(s->rb, frame_count * frame_size);
                bytecnt = ringbuffer_writable_size(s->rb);
            }

            bytecnt = MIN(bytecnt, frame_count * frame_size);
            bytecnt = MIN(bytecnt, sizeof(buf));

            if (bytecnt > 0) {
                snd_pcm_readi(s->ph, buf, bytecnt / frame_size);
                ringbuffer_write(s->rb, buf, bytecnt);
            }

            size_t readable_size = pa_stream_readable_size(s);
            if (s->read_cb && readable_size > 0)
                s->read_cb(s, readable_size, s->read_cb_userdata);
        }
    }
}
Example #12
0
/* Read samples from the PulseAudio device.
 * Samples are converted to complex form based upon format, counted
 * and returned via cSamples pointer.
 * Returns the number of samples placed into cSamples
 */
int quisk_read_pulseaudio(struct sound_dev *dev, complex double *cSamples) {
    int i, nSamples;
    int read_frames;		// A frame is a sample from each channel
    const void * fbuffer;
    pa_stream *s = dev->handle;
    size_t read_bytes;
    
    if (!dev)
        return 0;

    if (dev->cork_status) {
        if (dev->read_frames != 0) {
            WaitForPoll();
        }
        return 0;
    }

   // Note: Access to PulseAudio data from our sound thread requires locking the threaded mainloop.
    if (dev->read_frames == 0) {		// non-blocking: read available frames
        pa_threaded_mainloop_lock(pa_ml);
        read_frames = pa_stream_readable_size(s) / dev->num_channels / dev->sample_bytes;
        
        if (read_frames == 0) {
            pa_threaded_mainloop_unlock(pa_ml);
            return 0;
        }
        dev->dev_latency = read_frames * dev->num_channels * 1000 / (dev->sample_rate / 1000);
        
    }
    
    else {		// Blocking read for dev->read_frames total frames
        WaitForPoll();
        pa_threaded_mainloop_lock(pa_ml);
        read_frames = pa_stream_readable_size(s) / dev->num_channels / dev->sample_bytes;
        
        if (read_frames == 0) {
            pa_threaded_mainloop_unlock(pa_ml);
            return 0;
        }
        dev->dev_latency = read_frames * dev->num_channels * 1000 / (dev->sample_rate / 1000);
    }
    
    
    nSamples = 0;
    
   while (nSamples < read_frames) {		// read samples in chunks until we have enough samples
       if (pa_stream_peek (s, &fbuffer, &read_bytes) < 0) {
           printf("Failure of pa_stream_peek in quisk_read_pulseaudio\n");
           pa_threaded_mainloop_unlock(pa_ml);
           return nSamples;
       }
       
       if (fbuffer == NULL && read_bytes == 0) {		// buffer is empty
           break;
       }
       
       if (fbuffer == NULL) {		// there is a hole in the buffer
           pa_stream_drop(s);
           continue;
       }
       
       if (nSamples * dev->num_channels * dev->sample_bytes + read_bytes >= SAMP_BUFFER_SIZE) {
           if (quisk_sound_state.verbose_pulse)
               printf("buffer full on %s\n", dev->name);
           pa_stream_drop(s);		// limit read request to buffer size
           break;
       }
       
       // Convert sampled data to complex data. dev->num_channels must be 2.
       if (dev->sample_bytes == 4) {  //float32
           float fi, fq;
           
           for( i = 0; i < read_bytes; i += (dev->num_channels * 4)) {
               memcpy(&fi, fbuffer + i + (dev->channel_I * 4), 4);
               memcpy(&fq, fbuffer + i + (dev->channel_Q * 4), 4);
               if (fi >=  1.0 || fi <= -1.0)
                   dev->overrange++;
               if (fq >=  1.0 || fq <= -1.0)
                   dev->overrange++;
               cSamples[nSamples++] = (fi + I * fq) * CLIP32;
           }
       }
       
       else if (dev->sample_bytes == 2) { //16bit integer little-endian
           int16_t si, sq;
           for( i = 0; i < read_bytes; i += (dev->num_channels * 2)) {
               memcpy(&si, fbuffer + i + (dev->channel_I * 2), 2);
               memcpy(&sq, fbuffer + i + (dev->channel_Q * 2), 2);
               if (si >= CLIP16  || si <= -CLIP16)
                   dev->overrange++;
               if (sq >= CLIP16 || sq <= -CLIP16)
                   dev->overrange++;
               int ii = si << 16;
               int qq = sq << 16;
               cSamples[nSamples++] = ii + I * qq;
           }
       }
       
       else {
           printf("Unknown sample size for %s", dev->name);
       }
       pa_stream_drop(s);
    }
    pa_threaded_mainloop_unlock(pa_ml);
   
    // DC removal; R.G. Lyons page 553
    complex double c;
    for (i = 0; i < nSamples; i++) {
        c = cSamples[i] + dev->dc_remove * 0.95;
        cSamples[i] = c - dev->dc_remove;
        dev->dc_remove = c;
    }
    return nSamples;
}