static void stream_request_cb(pa_stream *s, size_t length, void *data) { M6502 *mpu = (M6502 *) data; int max = 0; redraw = 0; pa_stream_begin_write(s, (void**) &sndbuf, &length); memset(sndbuf, 128, length); max = length * 6250 / 539; if (max > 20454) fprintf(stderr, "Cycles = %u!\n", (unsigned int) max); cycles = 0; while (cycles < max) { if (trace) M6502_disassemble(mpu); cycles += M6502_run(mpu); } pa_stream_write(s, sndbuf, length, NULL, 0, PA_SEEK_RELATIVE); redraw = 1; }
void PulseAudioDriver::stream_write_callback(pa_stream* stream, size_t bytes, void* udata) { PulseAudioDriver* self = (PulseAudioDriver*)udata; void* vdata; pa_stream_begin_write(stream, &vdata, &bytes); if (!vdata) return; short* out = (short*)vdata; unsigned num_samples = bytes / 4; while (num_samples) { int n = std::min(self->m_buffer_size, num_samples); self->m_callback(n, 0); for (int i = 0; i < n; ++i) { *out++ = FLOAT_TO_SHORT(self->m_outL[i]); *out++ = FLOAT_TO_SHORT(self->m_outR[i]); } num_samples -= n; } pa_stream_write(stream, vdata, (bytes / 4) * 4, 0, 0, PA_SEEK_RELATIVE); }
/* This is called whenever new data may be written to the stream */ static void stream_write_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_INPUT); if (!buffer) return; do_stream_write(length); } else { sf_count_t bytes; void *data; pa_assert(sndfile); for (;;) { size_t data_length = length; if (pa_stream_begin_write(s, &data, &data_length) < 0) { pa_log(_("pa_stream_begin_write() failed: %s"), pa_strerror(pa_context_errno(context))); quit(1); return; } if (readf_function) { size_t k = pa_frame_size(&sample_spec); if ((bytes = readf_function(sndfile, data, (sf_count_t) (data_length/k))) > 0) bytes *= (sf_count_t) k; } else bytes = sf_read_raw(sndfile, data, (sf_count_t) data_length); if (bytes > 0) pa_stream_write(s, data, (size_t) bytes, NULL, 0, PA_SEEK_RELATIVE); else pa_stream_cancel_write(s); /* EOF? */ if (bytes < (sf_count_t) data_length) { start_drain(); break; } /* Request fulfilled */ if ((size_t) bytes >= length) break; length -= bytes; } } }
void PulseAudio::WriteCallback(pa_stream* s, size_t length) { // fetch dst buffer directly from pulseaudio, so no memcpy is needed void* buffer; m_pa_error = pa_stream_begin_write(s, &buffer, &length); if (!buffer || m_pa_error < 0) return; // error will be printed from main loop m_mixer->Mix((s16*) buffer, length / sizeof(s16) / CHANNEL_COUNT); m_pa_error = pa_stream_write(s, buffer, length, nullptr, 0, PA_SEEK_RELATIVE); }
JNIEXPORT jint JNICALL Java_org_jitsi_impl_neomedia_pulseaudio_PA_stream_1write (JNIEnv *env, jclass clazz, jlong s, jbyteArray data, jint dataOffset, jint dataLength, jobject freeCb, jlong offset, jint seek) { pa_stream *stream = (pa_stream *) (intptr_t) s; jbyte *bytes = NULL; size_t nbytes = dataLength; int ret; pa_stream_begin_write(stream, (void **) &bytes, &nbytes); if (bytes && nbytes) { if (nbytes < dataLength) dataLength = nbytes; (*env)->GetByteArrayRegion(env, data, dataOffset, dataLength, bytes); if ((*env)->ExceptionCheck(env)) ret = 0; else { pa_stream_write( stream, bytes, (size_t) dataLength, NULL, (int64_t) offset, (pa_seek_mode_t) seek); ret = dataLength; } } else { bytes = (*env)->GetByteArrayElements(env, data, NULL); if ((*env)->ExceptionCheck(env)) ret = 0; else { pa_stream_write( stream, bytes + dataOffset, (size_t) dataLength, NULL, (int64_t) offset, (pa_seek_mode_t) seek); (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT); ret = dataLength; } } return ret; }
static void stream_request_callback(pa_stream * s, size_t nbytes, void * u) { cubeb_stream * stm; void * buffer; size_t size; int r; long got; size_t towrite; size_t frame_size; stm = u; if (stm->shutdown) return; frame_size = pa_frame_size(&stm->sample_spec); assert(nbytes % frame_size == 0); towrite = nbytes; while (towrite) { size = towrite; r = pa_stream_begin_write(s, &buffer, &size); assert(r == 0); assert(size > 0); assert(size % frame_size == 0); got = stm->data_callback(stm, stm->user_ptr, buffer, size / frame_size); if (got < 0) { pa_stream_cancel_write(s); stm->shutdown = 1; return; } r = pa_stream_write(s, buffer, got * frame_size, NULL, 0, PA_SEEK_RELATIVE); assert(r == 0); if ((size_t) got < size / frame_size) { stm->draining = pa_stream_drain(s, stream_drain_success_callback, stm); stm->shutdown = 1; return; } towrite -= size; } assert(towrite == 0); }
static void stream_write_cb(pa_stream *p, size_t nbytes, void *userdata) { /* Just some silence */ for (;;) { void *data; fail_unless((nbytes = pa_stream_writable_size(p)) != (size_t) -1); if (nbytes <= 0) break; fail_unless(pa_stream_begin_write(p, &data, &nbytes) == 0); pa_memzero(data, nbytes); fail_unless(pa_stream_write(p, data, nbytes, NULL, 0, PA_SEEK_RELATIVE) == 0); } }
static ALuint PulseProc(ALvoid *param) { ALCdevice *Device = param; pulse_data *data = Device->ExtraData; ssize_t len; SetRTPriority(); pa_threaded_mainloop_lock(data->loop); do { len = (Device->Connected ? pa_stream_writable_size(data->stream) : 0); len -= len%(Device->UpdateSize*data->frame_size); if(len == 0) { pa_threaded_mainloop_wait(data->loop); continue; } while(len > 0) { size_t newlen = len; void *buf; pa_free_cb_t free_func = NULL; #if PA_CHECK_VERSION(0,9,16) if(!pa_stream_begin_write || pa_stream_begin_write(data->stream, &buf, &newlen) < 0) #endif { buf = pa_xmalloc(newlen); free_func = pa_xfree; } pa_threaded_mainloop_unlock(data->loop); aluMixData(Device, buf, newlen/data->frame_size); pa_threaded_mainloop_lock(data->loop); pa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE); len -= newlen; } } while(Device->Connected && !data->killNow); pa_threaded_mainloop_unlock(data->loop); return 0; }
static int outstream_begin_write_pa(struct SoundIoPrivate *si, struct SoundIoOutStreamPrivate *os, struct SoundIoChannelArea **out_areas, int *frame_count) { struct SoundIoOutStream *outstream = &os->pub; struct SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; pa_stream *stream = ospa->stream; ospa->write_byte_count = *frame_count * outstream->bytes_per_frame; if (pa_stream_begin_write(stream, (void**)&ospa->write_ptr, &ospa->write_byte_count)) return SoundIoErrorStreaming; for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) { ospa->areas[ch].ptr = ospa->write_ptr + outstream->bytes_per_sample * ch; ospa->areas[ch].step = outstream->bytes_per_frame; } *frame_count = ospa->write_byte_count / outstream->bytes_per_frame; *out_areas = ospa->areas; return 0; }
/****************************************************************************** * stream_write_cb() * This will be called by PulseAudio when we need to provide audio data * for playback. *****************************************************************************/ static void stream_write_cb(pa_stream *s, size_t n_requested_bytes, void *userdata) { _mbx_out out = (_mbx_out ) userdata; sample_t *data_to_write = NULL; size_t n_bytes_written = 0; assert ( out != NULL && out->stream == s); if ( out->trigger_shutdown ) { do_shutdown(out); return; } while ( n_bytes_written < n_requested_bytes ) { int r; size_t n_bytes_to_write = n_requested_bytes - n_bytes_written; r = pa_stream_begin_write(s, (void**)&data_to_write, &n_bytes_to_write); assert(n_bytes_to_write % (2*sizeof(sample_t)) == 0); if ( r < 0 ) { mbx_log_error(MBX_LOG_AUDIO_OUTPUT, "Prepare writing data to the pulseaudio server" " failed: %s", pa_msg(out)); pa_stream_cancel_write(s); return; } if ( n_bytes_to_write > 0 ) { int i; assert ( n_bytes_to_write / sizeof(sample_t) < 44100L*2*8 ); sample_t left[44100L*2*8]; sample_t right[44100L*2*8]; out->cb(left, right, n_bytes_to_write / (2*sizeof(sample_t)), out->output_cb_userdata); for ( i=0; i<n_bytes_to_write/(2*sizeof(sample_t)); i++ ) { data_to_write[2*i] = left[i]; data_to_write[2*i+1] = right[i]; } pa_stream_write(s, data_to_write, n_bytes_to_write, NULL, 0, PA_SEEK_RELATIVE); n_bytes_written += n_bytes_to_write; } } }
/*! Starts up audio streaming to the host. */ void HostAudio::open() { m_mainloop = pa_threaded_mainloop_new(); if (!m_mainloop) { qDebug("Could not acquire PulseAudio main loop"); return; } m_api = pa_threaded_mainloop_get_api(m_mainloop); m_context = pa_context_new(m_api, "emumaster"); pa_context_set_state_callback(m_context, contextStreamCallback, this); if (!m_context) { qDebug("Could not acquire PulseAudio device context"); return; } #if defined(MEEGO_EDITION_HARMATTAN) if (pa_context_connect(m_context, 0, PA_CONTEXT_NOFLAGS, 0) < 0) { #elif defined(Q_WS_MAEMO_5) if (pa_context_connect(m_context, 0, (pa_context_flags_t)0, 0) < 0) { #endif int error = pa_context_errno(m_context); qDebug("Could not connect to PulseAudio server: %s", pa_strerror(error)); return; } pa_threaded_mainloop_lock(m_mainloop); if (pa_threaded_mainloop_start(m_mainloop) < 0) { qDebug("Could not start mainloop"); return; } waitForStreamReady(); pa_sample_spec fmt; fmt.channels = 2; fmt.format = PA_SAMPLE_S16LE; fmt.rate = 44100; pa_buffer_attr buffer_attributes; buffer_attributes.tlength = pa_bytes_per_second(&fmt) / 5; buffer_attributes.maxlength = buffer_attributes.tlength * 3; buffer_attributes.minreq = buffer_attributes.tlength / 3; buffer_attributes.prebuf = buffer_attributes.tlength; m_stream = pa_stream_new(m_context, "emumaster", &fmt, 0); if (!m_stream) { int error = pa_context_errno(m_context); qDebug("Could not acquire new PulseAudio stream: %s", pa_strerror(error)); return; } pa_stream_flags_t flags = (pa_stream_flags_t)(PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE); // pa_stream_flags_t flags = (pa_stream_flags_t) (PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS); if (pa_stream_connect_playback(m_stream, 0, &buffer_attributes, flags, 0, 0) < 0) { m_stream = 0; int error = pa_context_errno(m_context); qDebug("Could not connect for playback: %s", pa_strerror(error)); return; } waitForStreamReady(); pa_threaded_mainloop_unlock(m_mainloop); } /*! Stops audio streaming. */ void HostAudio::close() { if (m_mainloop) pa_threaded_mainloop_stop(m_mainloop); if (m_stream) { pa_stream_unref(m_stream); m_stream = 0; } if (m_context) { pa_context_disconnect(m_context); pa_context_unref(m_context); m_context = 0; } if (m_mainloop) { pa_threaded_mainloop_free(m_mainloop); m_mainloop = 0; } } /*! Streams a frame of audio from emulated system to the host. */ void HostAudio::sendFrame() { if (!m_stream) return; pa_threaded_mainloop_lock(m_mainloop); void *data; #if defined(MEEGO_EDITION_HARMATTAN) size_t size = -1; pa_stream_begin_write(m_stream, &data, &size); #elif defined(Q_WS_MAEMO_5) size_t size = 4096; static char buf[4096]; data = buf; #endif size = qMin(size, pa_stream_writable_size(m_stream)); if (size) size = m_emu->fillAudioBuffer(reinterpret_cast<char *>(data), size); if (size) pa_stream_write(m_stream, data, size, 0, 0, PA_SEEK_RELATIVE); #if defined(MEEGO_EDITION_HARMATTAN) else pa_stream_cancel_write(m_stream); #endif pa_threaded_mainloop_unlock(m_mainloop); } /*! \internal */ void HostAudio::waitForStreamReady() { pa_context_state_t context_state = pa_context_get_state(m_context); while (context_state != PA_CONTEXT_READY) { context_state = pa_context_get_state(m_context); if (!PA_CONTEXT_IS_GOOD(context_state)) { int error = pa_context_errno(m_context); qDebug("Context state is not good: %s", pa_strerror(error)); return; } else if (context_state == PA_CONTEXT_READY) { break; } else { //qDebug("PulseAudio context state is %d", context_state); } pa_threaded_mainloop_wait(m_mainloop); } }
static ALuint PulseProc(ALvoid *param) { ALCdevice *Device = param; pulse_data *data = Device->ExtraData; ALuint buffer_size; ALint update_size; size_t frame_size; ssize_t len; SetRTPriority(); pa_threaded_mainloop_lock(data->loop); frame_size = pa_frame_size(&data->spec); update_size = Device->UpdateSize * frame_size; /* Sanitize buffer metrics, in case we actually have less than what we * asked for. */ buffer_size = minu(update_size*Device->NumUpdates, data->attr.tlength); update_size = minu(update_size, buffer_size/2); do { len = pa_stream_writable_size(data->stream) - data->attr.tlength + buffer_size; if(len < update_size) { if(pa_stream_is_corked(data->stream) == 1) { pa_operation *o; o = pa_stream_cork(data->stream, 0, NULL, NULL); if(o) pa_operation_unref(o); } pa_threaded_mainloop_unlock(data->loop); Sleep(1); pa_threaded_mainloop_lock(data->loop); continue; } len -= len%update_size; while(len > 0) { size_t newlen = len; void *buf; pa_free_cb_t free_func = NULL; #if PA_CHECK_VERSION(0,9,16) if(!pa_stream_begin_write || pa_stream_begin_write(data->stream, &buf, &newlen) < 0) #endif { buf = pa_xmalloc(newlen); free_func = pa_xfree; } pa_threaded_mainloop_unlock(data->loop); aluMixData(Device, buf, newlen/frame_size); pa_threaded_mainloop_lock(data->loop); pa_stream_write(data->stream, buf, newlen, free_func, 0, PA_SEEK_RELATIVE); len -= newlen; } } while(!data->killNow && Device->Connected); pa_threaded_mainloop_unlock(data->loop); return 0; }
static int pulseaudio_audio_deliver(audio_decoder_t *ad, int samples, int64_t pts, int epoch) { decoder_t *d = (decoder_t *)ad; size_t bytes; if(ad->ad_spdif_muxer != NULL) { bytes = ad->ad_spdif_frame_size; } else { bytes = samples * d->framesize; } void *buf; assert(d->s != NULL); pa_threaded_mainloop_lock(mainloop); int writable = pa_stream_writable_size(d->s); if(writable == 0) { d->blocked = 1; pa_threaded_mainloop_unlock(mainloop); return 1; } pa_stream_begin_write(d->s, &buf, &bytes); assert(bytes > 0); if(ad->ad_spdif_muxer != NULL) { memcpy(buf, ad->ad_spdif_frame, ad->ad_spdif_frame_size); } else { int rsamples = bytes / d->framesize; uint8_t *data[8] = {0}; data[0] = (uint8_t *)buf; assert(rsamples <= samples); avresample_read(ad->ad_avr, data, rsamples); } if(pts != AV_NOPTS_VALUE) { media_pipe_t *mp = ad->ad_mp; hts_mutex_lock(&mp->mp_clock_mutex); const pa_timing_info *ti = pa_stream_get_timing_info(d->s); if(ti != NULL) { mp->mp_audio_clock_avtime = ti->timestamp.tv_sec * 1000000LL + ti->timestamp.tv_usec; int64_t busec = pa_bytes_to_usec(ti->write_index - ti->read_index, &d->ss); int64_t delay = ti->sink_usec + busec + ti->transport_usec; mp->mp_audio_clock = pts - delay; mp->mp_audio_clock_epoch = epoch; } hts_mutex_unlock(&mp->mp_clock_mutex); } pa_stream_write(d->s, buf, bytes, NULL, 0LL, PA_SEEK_RELATIVE); ad->ad_spdif_frame_size = 0; pa_threaded_mainloop_unlock(mainloop); return 0; }
RTC::ReturnCode_t PulseAudioOutput::WriteBuffer(void) { // get writable length from audio library simple_recast *psimple = (simple_recast *)m_simple; pa_threaded_mainloop_lock(psimple->mainloop); RTC_DEBUG(("pa_threaded_mainloop_lock()")); size_t len = pa_stream_writable_size(psimple->stream); if (len == 0) { RTC_DEBUG(("WriteBufer: no writable buffer.")); pa_threaded_mainloop_unlock(psimple->mainloop); RTC_DEBUG(("pa_threaded_mainloop_unlock()")); return RTC::RTC_OK; } // now we copy the data from component buffer to audio device buffer m_mutex.lock(); RTC_DEBUG(("WriteBuffer: mutex lock")); RTC_DEBUG(("WriteBuffer: data buffer size: %i", m_data.size())); RTC_DEBUG(("WriteBuffer: device writable length: %i", len)); size_t nbytes = len; if (nbytes > m_data.size()) nbytes = m_data.size(); if (m_data.size() == 0) { if (len > m_bufferattr.tlength / 2) { RTC_DEBUG(("WriteBuffer: data buffer size is zero and device buffer size is low >> write zeros <<")); m_writezero = true; } if (m_writezero == false) { RTC_DEBUG(("WriteBufer: no writable data.")); pa_threaded_mainloop_unlock(psimple->mainloop); RTC_DEBUG(("pa_threaded_mainloop_unlock()")); m_mutex.unlock(); RTC_DEBUG(("WriteBuffer: mutex unlock")); return RTC::RTC_OK; } } else { m_writezero = false; } if (m_writezero == true) nbytes = len; if (nbytes > len) nbytes = len; // get a data buffer from the audio device void *data; RTC_DEBUG(("WriteBuffer: prepare to write %i bytes", nbytes)); if ( pa_stream_begin_write(psimple->stream, &data, &nbytes) < 0 ) { RTC_WARN(("pa_stream_begin_write() failed.", nbytes)); pa_threaded_mainloop_unlock(psimple->mainloop); RTC_DEBUG(("pa_threaded_mainloop_unlock()")); m_mutex.unlock(); RTC_DEBUG(("WriteBuffer: mutex unlock")); //return RTC::RTC_ERROR; // this sometimes happen (should retry) return RTC::RTC_OK; } // copy the data to the audio buffer RTC_DEBUG(("WriteBuffer: audio buffer dequeue start.")); unsigned char *buff = (unsigned char *)data; if (m_writezero == true) { for (unsigned long i = 0; i < (unsigned long)nbytes; i++) { *buff++ = 0; } } else { for (unsigned long i = 0; i < (unsigned long)nbytes; i++) { *buff++ = m_data.front(); m_data.pop_front(); } } RTC_DEBUG(("WriteBuffer: audio buffer dequeue finish.")); // set the data to the outport m_out_data.data.length(nbytes); //!< set outport data length memcpy((void *)&(m_out_data.data[0]), data, nbytes); RTC_DEBUG(("WriteBuffer: audio buffer copy complete.")); m_mutex.unlock(); RTC_DEBUG(("WriteBuffer: mutex unlock")); // send the data to the audio device if (pa_stream_write( psimple->stream, data, nbytes, NULL, 0, PA_SEEK_RELATIVE) < 0) { RTC_WARN(("pa_stream_write() failed.")); return RTC::RTC_ERROR; } pa_threaded_mainloop_unlock(psimple->mainloop); RTC_DEBUG(("pa_threaded_mainloop_unlock()")); // send the data to the outport setTimestamp( m_out_data ); m_out_dataOut.write(); RTC_DEBUG(("wrote stream data to AudioDataOut port")); return RTC::RTC_OK; }