[pulseaudio-discuss] Erratic read callbacks on nullsink monitor

Eric Thornton gonesurfingnc at yahoo.com
Tue Jun 9 21:02:22 PDT 2015


Strange question here, but I am hoping someone understands what's happening and can save me hours of debugging.

The application interface I'm writing uses the threaded mainloop. I asynchronously read into a ringbuffer from which I can synchronously read from in specific frame blocks. Being a sound processing application (Software defined radio), I need to be able to read from a nullsink monitor that is being written to by a separate application.  This is all fine and dandy with one separate application that I am using which writes to pulseaudio directly, but a second application I am using writes to the sink with a QTmultimedia backend and acts strangely...  The read callbacks space out and come sporadically, such as when there is no stream attached to the sink. However when I have pavucontrol open, the read callbacks come regularly and frequenty and everything works perfectly.  I've tested this on two different setups and have the same behavior with pulseaudio 4.0 and 5.0.  

I have a definite lack of understanding on how the nullsink.monitor works internally. It seems to me that read callbacks should happen weather a stream is attached the the nullsink or not, similar to a normal recording pulseaudio device.  Perhaps I have something mis-configured.  Buffer attributes and relevant stream setup shown in the code shown below. Nullsink created in default.pa with only "sink_name" as an option.

Thanks in advance,

Eric

static void server_info_cb(pa_context *c, const pa_server_info *info, void *userdata) {
struct sound_dev **pDevices = userdata;
printf("Connected to %s \n", info->host_name);

pa_buffer_attr rec_ba;
pa_buffer_attr play_ba;
pa_sample_spec ss;
pa_sample_spec default_ss;
pa_stream_flags_t flags = PA_STREAM_NOFLAGS;

default_ss = info->sample_spec;

while(*pDevices) {
struct sound_dev *dev = *pDevices++;
const char * dev_name;
pa_stream *s;

pa_zero(rec_ba);
pa_zero(play_ba);

if (dev->name[5] == ':')
dev_name = dev->name + 6;		// the device name is given; "pulse:alsa_input.pci-0000_00_1b.0.analog-stereo"
else
dev_name = NULL;			// the device name is "pulse" for the default device 

printf("Opening Device %s ", dev_name);

// Construct sample specification
ss.format = default_ss.format;
ss.rate = dev->sample_rate;
ss.channels = dev->num_channels;
dev->sample_bytes = (int)pa_frame_size(&ss) / ss.channels;

rec_ba.maxlength = (uint32_t) -1;
rec_ba.fragsize = (uint32_t) -1; 

play_ba.maxlength = (uint32_t) -1;
play_ba.prebuf = (uint32_t) (dev->sample_bytes * ss.channels * dev->latency_frames);
play_ba.tlength = (uint32_t) (dev->sample_bytes * ss.channels * dev->latency_frames);
if (dev->latency_frames == 0)
play_ba.minreq = (uint32_t) 0; //verify this is sane
else 
play_ba.minreq = (uint32_t) -1;

if (strncmp(dev->stream_direction, "RECORD",7) == 0) {

if (!(s = pa_stream_new(c, dev->stream_description, &ss, NULL))) {
printf("pa_stream_new() failed: %s", pa_strerror(pa_context_errno(c)));
exit(1);
}
if (pa_stream_connect_record(s, dev_name, &rec_ba, flags) < 0) {
printf("pa_stream_connect_record() failed: %s", pa_strerror(pa_context_errno(c)));
exit(1);
}
pa_stream_set_overflow_callback(s, stream_overflow_callback, dev);
pa_stream_set_read_callback(s, stream_read_callback, dev);
printf("read_frames %d", dev->read_frames);

//Ringbuffer initialization for each read device
dev->rbuff_data = pa_xmalloc(SAMP_RB_SIZE);
printf(" Ringbuffer size %u \n", SAMP_RB_SIZE);

if (PaUtil_InitializeRingBuffer(&dev->rbuff, 1, SAMP_RB_SIZE, dev->rbuff_data) <0 ) {
printf("Ringbuffer size must be power of 2.");
exit(1);
}
}

else {
pa_cvolume cv;
pa_volume_t volume = PA_VOLUME_NORM;

if (!(s = pa_stream_new(c, dev->stream_description, &ss, NULL))) {
printf("pa_stream_new() failed: %s", pa_strerror(pa_context_errno(c)));
exit(1);
}
if (pa_stream_connect_playback(s, dev_name, &play_ba, flags, pa_cvolume_set(&cv, ss.channels, volume), NULL) < 0) {
printf("pa_stream_connect_playback() failed: %s", pa_strerror(pa_context_errno(c)));
exit(1); //goto fail;
} 
pa_stream_set_underflow_callback(s, stream_underflow_callback, dev);
}

pa_stream_set_state_callback(s, stream_state_callback, dev);
pa_stream_set_started_callback(s, stream_started_callback, dev);
dev->handle = (void*)s; //save memory address for stream in handle
int i;
for(i=0;i < PA_LIST_SIZE;i++) {
if (!(OpenPulseDevices[i])) {
OpenPulseDevices[i] = dev->handle;
break; 
}
}

}

}


More information about the pulseaudio-discuss mailing list