/***************************************************************************** * Close: close the audio device *****************************************************************************/ static void Close ( vlc_object_t *p_this ) { aout_instance_t *p_aout = (aout_instance_t *)p_this; struct aout_sys_t * p_sys = p_aout->output.p_sys; msg_Dbg(p_aout, "Pulse Close"); if(p_sys->stream) { pa_threaded_mainloop_lock(p_sys->mainloop); pa_stream_set_write_callback(p_sys->stream, NULL, NULL); pa_operation *o; o = pa_stream_flush(p_sys->stream, success_cb, p_aout); while( pa_operation_get_state(o) == PA_OPERATION_RUNNING ) pa_threaded_mainloop_wait(p_sys->mainloop); pa_operation_unref(o); o = pa_stream_drain(p_sys->stream, success_cb, p_aout); while( pa_operation_get_state(o) == PA_OPERATION_RUNNING ) pa_threaded_mainloop_wait(p_sys->mainloop); pa_operation_unref(o); pa_threaded_mainloop_unlock(p_sys->mainloop); } uninit(p_aout); }
void PulseAudioPlayer::Stop() { if (!is_playing) return; //printf("Stopping PulseAudio\n"); is_playing = false; start_frame = 0; cur_frame = 0; end_frame = 0; // Flush the stream of data //printf("Flushing stream\n"); pa_threaded_mainloop_lock(mainloop); pa_operation *op = pa_stream_flush(stream, (pa_stream_success_cb_t)pa_stream_success, this); pa_threaded_mainloop_unlock(mainloop); stream_success.Wait(); pa_operation_unref(op); if (!stream_success_val) { paerror = pa_context_errno(context); printf("PulseAudio player: Error flushing stream: %s (%d)\n", pa_strerror(paerror), paerror); } // And unref it //printf("Stopped stream\n\n"); }
int pa_simple_flush(pa_simple *p, int *rerror) { pa_operation *o = NULL; pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); pa_threaded_mainloop_lock(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); o = pa_stream_flush(p->stream, success_cb, p); CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); p->operation_success = 0; while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); pa_operation_unref(o); pa_threaded_mainloop_unlock(p->mainloop); return 0; unlock_and_fail: if (o) { pa_operation_cancel(o); pa_operation_unref(o); } pa_threaded_mainloop_unlock(p->mainloop); return -1; }
static void pulse_output_cancel(struct audio_output *ao) { struct pulse_output *po = (struct pulse_output *)ao; pa_operation *o; assert(po->mainloop != NULL); assert(po->stream != NULL); pa_threaded_mainloop_lock(po->mainloop); if (pa_stream_get_state(po->stream) != PA_STREAM_READY) { /* no need to flush when the stream isn't connected yet */ pa_threaded_mainloop_unlock(po->mainloop); return; } assert(po->context != NULL); o = pa_stream_flush(po->stream, pulse_output_stream_success_cb, po); if (o == NULL) { g_warning("pa_stream_flush() has failed: %s", pa_strerror(pa_context_errno(po->context))); pa_threaded_mainloop_unlock(po->mainloop); return; } pulse_wait_for_operation(po->mainloop, o); pa_threaded_mainloop_unlock(po->mainloop); }
static void pulse_flush(int time) { pa_operation *o = NULL; int success = 0; CHECK_CONNECTED(); pa_threaded_mainloop_lock(mainloop); CHECK_DEAD_GOTO(fail, 1); written = time * (int64_t) bytes_per_second / 1000; flush_time = time; if (!(o = pa_stream_flush(stream, stream_success_cb, &success))) { AUDDBG("pa_stream_flush() failed: %s", pa_strerror(pa_context_errno(context))); goto fail; } while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CHECK_DEAD_GOTO(fail, 1); pa_threaded_mainloop_wait(mainloop); } if (!success) AUDDBG("pa_stream_flush() failed: %s", pa_strerror(pa_context_errno(context))); fail: if (o) pa_operation_unref(o); pa_threaded_mainloop_unlock(mainloop); }
/** Reset the audio stream, i.e. flush the playback buffer on the server side */ static void reset(void) { int success = 0; pa_threaded_mainloop_lock(mainloop); if (!waitop(pa_stream_flush(stream, success_cb, &success)) || !success) GENERIC_ERR_MSG(context, "pa_stream_flush() failed"); }
static void tsmf_pulse_flush(ITSMFAudioDevice *audio) { TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; pa_threaded_mainloop_lock(pulse->mainloop); tsmf_pulse_wait_for_operation(pulse, pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); pa_threaded_mainloop_unlock(pulse->mainloop); }
void CPulseAEStream::Flush() { if (!m_Initialized) return; pa_threaded_mainloop_lock(m_MainLoop); pa_operation_unref(pa_stream_flush(m_Stream, NULL, NULL)); pa_threaded_mainloop_unlock(m_MainLoop); }
void AudioOutputPulseAudio::FlushStream(const char *caller) { QString fn_log_tag = QString("FlushStream (%1), ").arg(caller); pa_threaded_mainloop_lock(mainloop); pa_operation *op = pa_stream_flush(pstream, NULL, this); pa_threaded_mainloop_unlock(mainloop); if (op) pa_operation_unref(op); else VBERROR(fn_log_tag + "stream flush operation failed "); }
static void pulseaudio_audio_flush(audio_decoder_t *ad) { decoder_t *d = (decoder_t *)ad; if(d->s == NULL) return; pa_threaded_mainloop_lock(mainloop); pa_operation *o = pa_stream_flush(d->s, NULL, NULL); if(o != NULL) pa_operation_unref(o); pa_threaded_mainloop_unlock(mainloop); }
static void stream_overflow_cb(pa_stream *s, void *userdata) { audio_output_t *aout = userdata; aout_sys_t *sys = aout->sys; pa_operation *op; msg_Err(aout, "overflow, flushing"); op = pa_stream_flush(s, NULL, NULL); if (unlikely(op == NULL)) return; pa_operation_unref(op); sys->first_pts = VLC_TS_INVALID; }
static void gst_pulsesrc_reset (GstAudioSrc * asrc) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_operation *o = NULL; pa_threaded_mainloop_lock (pulsesrc->mainloop); GST_DEBUG_OBJECT (pulsesrc, "reset"); if (gst_pulsesrc_is_dead (pulsesrc, TRUE)) goto unlock_and_fail; if (!(o = pa_stream_flush (pulsesrc->stream, gst_pulsesrc_success_cb, pulsesrc))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_stream_flush() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } pulsesrc->paused = TRUE; /* Inform anyone waiting in _write() call that it shall wakeup */ if (pulsesrc->in_read) { pa_threaded_mainloop_signal (pulsesrc->mainloop, 0); } pulsesrc->operation_success = FALSE; while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) { if (gst_pulsesrc_is_dead (pulsesrc, TRUE)) goto unlock_and_fail; pa_threaded_mainloop_wait (pulsesrc->mainloop); } if (!pulsesrc->operation_success) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Flush failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } unlock_and_fail: if (o) { pa_operation_cancel (o); pa_operation_unref (o); } pa_threaded_mainloop_unlock (pulsesrc->mainloop); }
static int outstream_clear_buffer_pa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { SoundIoOutStreamPulseAudio *ospa = &os->backend_data.pulseaudio; SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; pa_stream *stream = ospa->stream; pa_threaded_mainloop_lock(sipa->main_loop); pa_operation *op = pa_stream_flush(stream, NULL, NULL); if (!op) { pa_threaded_mainloop_unlock(sipa->main_loop); return SoundIoErrorStreaming; } pa_operation_unref(op); pa_threaded_mainloop_unlock(sipa->main_loop); return 0; }
void PulseAudioPlayer::Play(int64_t start,int64_t count) { //printf("Starting PulseAudio playback\n"); if (!open) OpenStream(); if (is_playing) { // If we're already playing, do a quick "reset" is_playing = false; pa_threaded_mainloop_lock(mainloop); pa_operation *op = pa_stream_flush(stream, (pa_stream_success_cb_t)pa_stream_success, this); pa_threaded_mainloop_unlock(mainloop); stream_success.Wait(); pa_operation_unref(op); if (!stream_success_val) { paerror = pa_context_errno(context); printf("PulseAudio player: Error flushing stream: %s (%d)\n", pa_strerror(paerror), paerror); } } start_frame = start; cur_frame = start; end_frame = start + count; //printf("start=%lu end=%lu\n", start_frame, end_frame); is_playing = true; play_start_time = 0; pa_threaded_mainloop_lock(mainloop); paerror = pa_stream_get_time(stream, (pa_usec_t*) &play_start_time); pa_threaded_mainloop_unlock(mainloop); if (paerror) { printf("PulseAudio player: Error getting stream time: %s (%d)\n", pa_strerror(paerror), paerror); } PulseAudioPlayer::pa_stream_write(stream, pa_stream_writable_size(stream), this); pa_threaded_mainloop_lock(mainloop); pa_operation *op = pa_stream_trigger(stream, (pa_stream_success_cb_t)pa_stream_success, this); pa_threaded_mainloop_unlock(mainloop); stream_success.Wait(); pa_operation_unref(op); if (!stream_success_val) { paerror = pa_context_errno(context); printf("PulseAudio player: Error triggering stream: %s (%d)\n", pa_strerror(paerror), paerror); } }
//Flush function. Holds mainloop lock until operation is completed. void quisk_flush_pulseaudio(struct sound_dev *dev) { pa_stream *s = dev->handle; pa_operation *o; pa_threaded_mainloop_lock(pa_ml); if (!(o = pa_stream_flush(s, stream_flushed_callback, dev))) { printf("pa_stream_flush(): %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s)))); exit(1); } else { while(pa_operation_get_state(o) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(pa_ml); pa_operation_unref(o); } pa_threaded_mainloop_unlock(pa_ml); }
static void cork_stream(struct userdata *u, bool cork) { pa_operation *operation; pa_assert(u); pa_assert(u->stream); if (cork) { /* When the sink becomes suspended (which is the only case where we * cork the stream), we don't want to keep any old data around, because * the old data is most likely unrelated to the audio that will be * played at the time when the sink starts running again. */ if ((operation = pa_stream_flush(u->stream, NULL, NULL))) pa_operation_unref(operation); } if ((operation = pa_stream_cork(u->stream, cork, NULL, NULL))) pa_operation_unref(operation); }
gpointer tick(gpointer _) { for(;;) { g_mutex_lock(tickmutex); g_cond_wait(tickcond,tickmutex); printf("tick %u (%u in %u)\n",offset,tickinbeat(),beatno()); print_stack(); g_idle_add(update_view,0); if(!jam) { if(execute()==-1) { pa_stream_cork(ps,1,corked,0); pa_stream_flush(ps,0,0); } } g_mutex_unlock(tickmutex); } return 0; }
gboolean xmms_pulse_backend_flush (xmms_pulse *p, int *rerror) { pa_operation *o = NULL; pa_threaded_mainloop_lock (p->mainloop); if (!check_pulse_health (p, rerror)) goto unlock_and_fail; o = pa_stream_flush (p->stream, drain_result_cb, p); if (!o) { if (rerror) *rerror = pa_context_errno ((p)->context); goto unlock_and_fail; } p->operation_success = 0; while (pa_operation_get_state (o) != PA_OPERATION_DONE) { pa_threaded_mainloop_wait (p->mainloop); if (!check_pulse_health (p, rerror)) goto unlock_and_fail; } pa_operation_unref (o); o = NULL; if (!p->operation_success) { if (rerror) *rerror = pa_context_errno ((p)->context); goto unlock_and_fail; } pa_threaded_mainloop_unlock (p->mainloop); return 0; unlock_and_fail: if (o) { pa_operation_cancel (o); pa_operation_unref (o); } pa_threaded_mainloop_unlock (p->mainloop); return -1; }
/***************************************************************************** * Play: play a sound samples buffer *****************************************************************************/ static void Play( aout_instance_t * p_aout ) { struct aout_sys_t * p_sys = (struct aout_sys_t *) p_aout->output.p_sys; pa_operation *o; if(!p_sys->started){ msg_Dbg(p_aout, "Pulse stream started"); p_sys->start_date = aout_FifoFirstDate( p_aout, &p_aout->output.fifo ); p_sys->started = 1; pa_threaded_mainloop_lock(p_sys->mainloop); if((o = pa_stream_flush(p_sys->stream, success_cb, p_aout))){ pa_operation_unref(o); } pa_threaded_mainloop_unlock(p_sys->mainloop); pa_threaded_mainloop_signal(p_sys->mainloop, 0); } }
static int pa_audio_start(audio_mode_t *am, audio_fifo_t *af) { pa_audio_mode_t *pam = (pa_audio_mode_t *)am; audio_buf_t *ab = NULL; size_t l, length; int64_t pts; media_pipe_t *mp; int r = 0; pa_threaded_mainloop_lock(mainloop); #if PA_API_VERSION >= 12 pa_proplist *pl = pa_proplist_new(); pa_proplist_sets(pl, PA_PROP_APPLICATION_ID, "com.lonelycoder.hts.showtime"); pa_proplist_sets(pl, PA_PROP_APPLICATION_NAME, "Showtime"); /* Create a new connection context */ pam->context = pa_context_new_with_proplist(api, "Showtime", pl); pa_proplist_free(pl); #else pam->context = pa_context_new(api, "Showtime"); #endif if(pam->context == NULL) { pa_threaded_mainloop_unlock(mainloop); return -1; } pa_context_set_state_callback(pam->context, context_state_callback, pam); /* Connect the context */ if(pa_context_connect(pam->context, NULL, 0, NULL) < 0) { TRACE(TRACE_ERROR, "PA", "pa_context_connect() failed: %s", pa_strerror(pa_context_errno(pam->context))); pa_threaded_mainloop_unlock(mainloop); return -1; } /* Need at least one packet of audio */ /* Subscribe to updates of master volume */ pam->sub_mvol = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_FLOAT, set_mastervol, pam, PROP_TAG_ROOT, prop_mastervol, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); /* Subscribe to updates of master volume mute */ pam->sub_mute = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_INT, set_mastermute, pam, PROP_TAG_ROOT, prop_mastermute, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); while(1) { if(ab == NULL) { pa_threaded_mainloop_unlock(mainloop); ab = af_deq2(af, 1, am); pa_threaded_mainloop_lock(mainloop); if(ab == AF_EXIT) { ab = NULL; break; } } if(pa_context_get_state(pam->context) == PA_CONTEXT_TERMINATED || pa_context_get_state(pam->context) == PA_CONTEXT_FAILED) { r = -1; break; } if(pam->stream != NULL && (pam->cur_format != ab->ab_format || pam->cur_rate != ab->ab_samplerate || pam->cur_isfloat != ab->ab_isfloat)) { stream_destroy(pam); } if(pam->stream == NULL && pa_context_get_state(pam->context) == PA_CONTEXT_READY) { /* Context is ready, but we don't have a stream yet, set it up */ stream_setup(pam, ab); } if(pam->stream == NULL) { pa_threaded_mainloop_wait(mainloop); continue; } switch(pa_stream_get_state(pam->stream)) { case PA_STREAM_UNCONNECTED: case PA_STREAM_CREATING: pa_threaded_mainloop_wait(mainloop); continue; case PA_STREAM_READY: break; case PA_STREAM_TERMINATED: case PA_STREAM_FAILED: pa_stream_unref(pam->stream); pam->stream = NULL; char msg[100]; snprintf(msg, sizeof(msg), "Audio stream disconnected from " "PulseAudio server -- %s.", pa_strerror(pam->stream_error)); mp_flush(ab->ab_mp, 0); mp_enqueue_event(ab->ab_mp, event_create_str(EVENT_INTERNAL_PAUSE, msg)); audio_fifo_purge(af, NULL, NULL); if(ab != NULL) { ab_free(ab); ab = NULL; } continue; } if(ab->ab_flush) { pa_operation *o; o = pa_stream_flush(pam->stream, NULL, NULL); if(o != NULL) pa_operation_unref(o); ab->ab_flush = 0; } l = pa_stream_writable_size(pam->stream); if(l == 0) { pa_threaded_mainloop_wait(mainloop); continue; } length = ab->ab_frames * pa_frame_size(&pam->ss) - ab->ab_tmp; if(l > length) l = length; if((pts = ab->ab_pts) != AV_NOPTS_VALUE && ab->ab_mp != NULL) { int64_t pts; pa_usec_t delay; pts = ab->ab_pts; ab->ab_pts = AV_NOPTS_VALUE; if(!pa_stream_get_latency(pam->stream, &delay, NULL)) { mp = ab->ab_mp; hts_mutex_lock(&mp->mp_clock_mutex); mp->mp_audio_clock = pts - delay; mp->mp_audio_clock_realtime = showtime_get_ts(); mp->mp_audio_clock_epoch = ab->ab_epoch; hts_mutex_unlock(&mp->mp_clock_mutex); } } pa_stream_write(pam->stream, ab->ab_data + ab->ab_tmp, l, NULL, 0LL, PA_SEEK_RELATIVE); ab->ab_tmp += l; assert(ab->ab_tmp <= ab->ab_frames * pa_frame_size(&pam->ss)); if(ab->ab_frames * pa_frame_size(&pam->ss) == ab->ab_tmp) { ab_free(ab); ab = NULL; } } prop_unsubscribe(pam->sub_mvol); prop_unsubscribe(pam->sub_mute); if(pam->stream != NULL) stream_destroy(pam); pa_threaded_mainloop_unlock(mainloop); pa_context_unref(pam->context); if(ab != NULL) { ab_free(ab); ab = NULL; } return r; }
static int init(struct ao *ao, char *params) { struct pa_sample_spec ss; struct pa_channel_map map; char *devarg = NULL; char *host = NULL; char *sink = NULL; const char *version = pa_get_library_version(); struct priv *priv = talloc_zero(ao, struct priv); ao->priv = priv; if (params) { devarg = strdup(params); sink = strchr(devarg, ':'); if (sink) *sink++ = 0; if (devarg[0]) host = devarg; } priv->broken_pause = false; /* not sure which versions are affected, assume 0.9.11* to 0.9.14* * known bad: 0.9.14, 0.9.13 * known good: 0.9.9, 0.9.10, 0.9.15 * To test: pause, wait ca. 5 seconds, framestep and see if MPlayer * hangs somewhen. */ if (strncmp(version, "0.9.1", 5) == 0 && version[5] >= '1' && version[5] <= '4') { mp_msg(MSGT_AO, MSGL_WARN, "[pulse] working around probably broken pause functionality,\n" " see http://www.pulseaudio.org/ticket/440\n"); priv->broken_pause = true; } ss.channels = ao->channels; ss.rate = ao->samplerate; const struct format_map *fmt_map = format_maps; while (fmt_map->mp_format != ao->format) { if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) { mp_msg(MSGT_AO, MSGL_V, "AO: [pulse] Unsupported format, using default\n"); fmt_map = format_maps; break; } fmt_map++; } ao->format = fmt_map->mp_format; ss.format = fmt_map->pa_format; if (!pa_sample_spec_valid(&ss)) { mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n"); goto fail; } pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); ao->bps = pa_bytes_per_second(&ss); if (!(priv->mainloop = pa_threaded_mainloop_new())) { mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n"); goto fail; } if (!(priv->context = pa_context_new(pa_threaded_mainloop_get_api( priv->mainloop), PULSE_CLIENT_NAME))) { mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate context\n"); goto fail; } pa_context_set_state_callback(priv->context, context_state_cb, ao); if (pa_context_connect(priv->context, host, 0, NULL) < 0) goto fail; pa_threaded_mainloop_lock(priv->mainloop); if (pa_threaded_mainloop_start(priv->mainloop) < 0) goto unlock_and_fail; /* Wait until the context is ready */ pa_threaded_mainloop_wait(priv->mainloop); if (pa_context_get_state(priv->context) != PA_CONTEXT_READY) goto unlock_and_fail; if (!(priv->stream = pa_stream_new(priv->context, "audio stream", &ss, &map))) goto unlock_and_fail; pa_stream_set_state_callback(priv->stream, stream_state_cb, ao); pa_stream_set_write_callback(priv->stream, stream_request_cb, ao); pa_stream_set_latency_update_callback(priv->stream, stream_latency_update_cb, ao); pa_buffer_attr bufattr = { .maxlength = -1, .tlength = pa_usec_to_bytes(1000000, &ss), .prebuf = -1, .minreq = -1, .fragsize = -1, }; if (pa_stream_connect_playback(priv->stream, sink, &bufattr, PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) goto unlock_and_fail; /* Wait until the stream is ready */ pa_threaded_mainloop_wait(priv->mainloop); if (pa_stream_get_state(priv->stream) != PA_STREAM_READY) goto unlock_and_fail; pa_threaded_mainloop_unlock(priv->mainloop); free(devarg); return 0; unlock_and_fail: if (priv->mainloop) pa_threaded_mainloop_unlock(priv->mainloop); fail: if (priv->context) GENERIC_ERR_MSG(priv->context, "Init failed"); free(devarg); uninit(ao, true); return -1; } static void cork(struct ao *ao, bool pause) { struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); priv->retval = 0; if (!waitop(priv, pa_stream_cork(priv->stream, pause, success_cb, ao)) || !priv->retval) GENERIC_ERR_MSG(priv->context, "pa_stream_cork() failed"); } // Play the specified data to the pulseaudio server static int play(struct ao *ao, void *data, int len, int flags) { struct priv *priv = ao->priv; /* For some reason Pulseaudio behaves worse if this is done after * the write - rapidly repeated seeks result in bogus increasing * reported latency. */ if (priv->did_reset) cork(ao, false); pa_threaded_mainloop_lock(priv->mainloop); if (pa_stream_write(priv->stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) { GENERIC_ERR_MSG(priv->context, "pa_stream_write() failed"); len = -1; } if (priv->did_reset) { priv->did_reset = false; if (!waitop(priv, pa_stream_update_timing_info(priv->stream, success_cb, ao)) || !priv->retval) GENERIC_ERR_MSG(priv->context, "pa_stream_UPP() failed"); } else pa_threaded_mainloop_unlock(priv->mainloop); return len; } // Reset the audio stream, i.e. flush the playback buffer on the server side static void reset(struct ao *ao) { // pa_stream_flush() works badly if not corked cork(ao, true); struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); priv->retval = 0; if (!waitop(priv, pa_stream_flush(priv->stream, success_cb, ao)) || !priv->retval) GENERIC_ERR_MSG(priv->context, "pa_stream_flush() failed"); priv->did_reset = true; }
void PulseOutput::drop() { if (stream) { pa_operation* operation = pa_stream_flush(stream,nullptr,0); pa_operation_unref(operation); } }
/** Reset the audio stream, i.e. flush the playback buffer on the server side */ static void reset(void) { assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY); wait_for_operation(pa_stream_flush(stream, NULL, NULL)); }
static int init(struct ao *ao) { pa_proplist *proplist = NULL; pa_format_info *format = NULL; struct priv *priv = ao->priv; char *sink = priv->cfg_sink && priv->cfg_sink[0] ? priv->cfg_sink : ao->device; if (pa_init_boilerplate(ao) < 0) return -1; pa_threaded_mainloop_lock(priv->mainloop); if (!(proplist = pa_proplist_new())) { MP_ERR(ao, "Failed to allocate proplist\n"); goto unlock_and_fail; } (void)pa_proplist_sets(proplist, PA_PROP_MEDIA_ICON_NAME, ao->client_name); if (!(format = pa_format_info_new())) goto unlock_and_fail; if (!set_format(ao, format)) { ao->channels = (struct mp_chmap) MP_CHMAP_INIT_STEREO; ao->samplerate = 48000; ao->format = AF_FORMAT_FLOAT; if (!set_format(ao, format)) { MP_ERR(ao, "Invalid audio format\n"); goto unlock_and_fail; } } if (!(priv->stream = pa_stream_new_extended(priv->context, "audio stream", &format, 1, proplist))) goto unlock_and_fail; pa_format_info_free(format); format = NULL; pa_proplist_free(proplist); proplist = NULL; pa_stream_set_state_callback(priv->stream, stream_state_cb, ao); pa_stream_set_write_callback(priv->stream, stream_request_cb, ao); pa_stream_set_latency_update_callback(priv->stream, stream_latency_update_cb, ao); int buf_size = af_fmt_seconds_to_bytes(ao->format, priv->cfg_buffer / 1000.0, ao->channels.num, ao->samplerate); pa_buffer_attr bufattr = { .maxlength = -1, .tlength = buf_size > 0 ? buf_size : (uint32_t)-1, .prebuf = -1, .minreq = -1, .fragsize = -1, }; int flags = PA_STREAM_NOT_MONOTONIC; if (!priv->cfg_latency_hacks) flags |= PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE; if (pa_stream_connect_playback(priv->stream, sink, &bufattr, flags, NULL, NULL) < 0) goto unlock_and_fail; /* Wait until the stream is ready */ while (1) { int state = pa_stream_get_state(priv->stream); if (state == PA_STREAM_READY) break; if (!PA_STREAM_IS_GOOD(state)) goto unlock_and_fail; pa_threaded_mainloop_wait(priv->mainloop); } if (pa_stream_is_suspended(priv->stream)) { MP_ERR(ao, "The stream is suspended. Bailing out.\n"); goto unlock_and_fail; } pa_threaded_mainloop_unlock(priv->mainloop); return 0; unlock_and_fail: pa_threaded_mainloop_unlock(priv->mainloop); if (format) pa_format_info_free(format); if (proplist) pa_proplist_free(proplist); uninit(ao); return -1; } static void cork(struct ao *ao, bool pause) { struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); priv->retval = 0; if (!waitop(priv, pa_stream_cork(priv->stream, pause, success_cb, ao)) || !priv->retval) GENERIC_ERR_MSG("pa_stream_cork() failed"); } // Play the specified data to the pulseaudio server static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); if (pa_stream_write(priv->stream, data[0], samples * ao->sstride, NULL, 0, PA_SEEK_RELATIVE) < 0) { GENERIC_ERR_MSG("pa_stream_write() failed"); samples = -1; } if (flags & AOPLAY_FINAL_CHUNK) { // Force start in case the stream was too short for prebuf pa_operation *op = pa_stream_trigger(priv->stream, NULL, NULL); pa_operation_unref(op); } pa_threaded_mainloop_unlock(priv->mainloop); return samples; } // Reset the audio stream, i.e. flush the playback buffer on the server side static void reset(struct ao *ao) { // pa_stream_flush() works badly if not corked cork(ao, true); struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); priv->retval = 0; if (!waitop(priv, pa_stream_flush(priv->stream, success_cb, ao)) || !priv->retval) GENERIC_ERR_MSG("pa_stream_flush() failed"); cork(ao, false); }
static int init(struct ao *ao) { struct pa_sample_spec ss; struct pa_channel_map map; pa_proplist *proplist = NULL; struct priv *priv = ao->priv; char *host = priv->cfg_host && priv->cfg_host[0] ? priv->cfg_host : NULL; char *sink = priv->cfg_sink && priv->cfg_sink[0] ? priv->cfg_sink : NULL; const char *version = pa_get_library_version(); ao->per_application_mixer = true; priv->broken_pause = false; /* not sure which versions are affected, assume 0.9.11* to 0.9.14* * known bad: 0.9.14, 0.9.13 * known good: 0.9.9, 0.9.10, 0.9.15 * To test: pause, wait ca. 5 seconds, framestep and see if MPlayer * hangs somewhen. */ if (strncmp(version, "0.9.1", 5) == 0 && version[5] >= '1' && version[5] <= '4') { MP_WARN(ao, "working around probably broken pause functionality,\n" " see http://www.pulseaudio.org/ticket/440\n"); priv->broken_pause = true; } if (!(priv->mainloop = pa_threaded_mainloop_new())) { MP_ERR(ao, "Failed to allocate main loop\n"); goto fail; } if (!(priv->context = pa_context_new(pa_threaded_mainloop_get_api( priv->mainloop), PULSE_CLIENT_NAME))) { MP_ERR(ao, "Failed to allocate context\n"); goto fail; } pa_context_set_state_callback(priv->context, context_state_cb, ao); if (pa_context_connect(priv->context, host, 0, NULL) < 0) goto fail; pa_threaded_mainloop_lock(priv->mainloop); if (pa_threaded_mainloop_start(priv->mainloop) < 0) goto unlock_and_fail; /* Wait until the context is ready */ pa_threaded_mainloop_wait(priv->mainloop); if (pa_context_get_state(priv->context) != PA_CONTEXT_READY) goto unlock_and_fail; ss.channels = ao->channels.num; ss.rate = ao->samplerate; ao->format = af_fmt_from_planar(ao->format); const struct format_map *fmt_map = format_maps; while (fmt_map->mp_format != ao->format) { if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) { MP_VERBOSE(ao, "Unsupported format, using default\n"); fmt_map = format_maps; break; } fmt_map++; } ao->format = fmt_map->mp_format; ss.format = fmt_map->pa_format; if (!pa_sample_spec_valid(&ss)) { MP_ERR(ao, "Invalid sample spec\n"); goto unlock_and_fail; } if (!select_chmap(ao, &map)) goto unlock_and_fail; if (!(proplist = pa_proplist_new())) { MP_ERR(ao, "Failed to allocate proplist\n"); goto unlock_and_fail; } (void)pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "video"); if (!(priv->stream = pa_stream_new_with_proplist(priv->context, "audio stream", &ss, &map, proplist))) goto unlock_and_fail; pa_proplist_free(proplist); proplist = NULL; pa_stream_set_state_callback(priv->stream, stream_state_cb, ao); pa_stream_set_write_callback(priv->stream, stream_request_cb, ao); pa_stream_set_latency_update_callback(priv->stream, stream_latency_update_cb, ao); pa_buffer_attr bufattr = { .maxlength = -1, .tlength = pa_usec_to_bytes(1000000, &ss), .prebuf = -1, .minreq = -1, .fragsize = -1, }; if (pa_stream_connect_playback(priv->stream, sink, &bufattr, PA_STREAM_NOT_MONOTONIC, NULL, NULL) < 0) goto unlock_and_fail; /* Wait until the stream is ready */ pa_threaded_mainloop_wait(priv->mainloop); if (pa_stream_get_state(priv->stream) != PA_STREAM_READY) goto unlock_and_fail; pa_threaded_mainloop_unlock(priv->mainloop); return 0; unlock_and_fail: if (priv->mainloop) pa_threaded_mainloop_unlock(priv->mainloop); fail: if (priv->context) { if (!(pa_context_errno(priv->context) == PA_ERR_CONNECTIONREFUSED && ao->probing)) GENERIC_ERR_MSG("Init failed"); } if (proplist) pa_proplist_free(proplist); uninit(ao, true); return -1; } static void cork(struct ao *ao, bool pause) { struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); priv->retval = 0; if (!waitop(priv, pa_stream_cork(priv->stream, pause, success_cb, ao)) || !priv->retval) GENERIC_ERR_MSG("pa_stream_cork() failed"); } // Play the specified data to the pulseaudio server static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); if (pa_stream_write(priv->stream, data[0], samples * ao->sstride, NULL, 0, PA_SEEK_RELATIVE) < 0) { GENERIC_ERR_MSG("pa_stream_write() failed"); samples = -1; } if (flags & AOPLAY_FINAL_CHUNK) { // Force start in case the stream was too short for prebuf pa_operation *op = pa_stream_trigger(priv->stream, NULL, NULL); pa_operation_unref(op); } pa_threaded_mainloop_unlock(priv->mainloop); return samples; } // Reset the audio stream, i.e. flush the playback buffer on the server side static void reset(struct ao *ao) { // pa_stream_flush() works badly if not corked cork(ao, true); struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); priv->retval = 0; if (!waitop(priv, pa_stream_flush(priv->stream, success_cb, ao)) || !priv->retval) GENERIC_ERR_MSG("pa_stream_flush() failed"); cork(ao, false); }