示例#1
0
static gboolean check_pulse_health (xmms_pulse *p, int *rerror)
{
	if (!p->context || pa_context_get_state (p->context) != PA_CONTEXT_READY ||
	    !p->stream || pa_stream_get_state (p->stream) != PA_STREAM_READY) {
		if ((p->context &&
		     pa_context_get_state (p->context) == PA_CONTEXT_FAILED) ||
		    (p->stream &&
		     pa_stream_get_state (p->stream) == PA_STREAM_FAILED)) {
			if (rerror)
				*(rerror) = pa_context_errno (p->context);
		} else if (rerror)
			*(rerror) = PA_ERR_BADSTATE;
		return FALSE;
	}
	return TRUE;
}
示例#2
0
static void inputStreamStateCallback(pa_stream *stream, void *userdata)
{
    Q_UNUSED(userdata);
    pa_stream_state_t state = pa_stream_get_state(stream);
#ifdef DEBUG_PULSE
    qDebug() << "Stream state: " << QPulseAudioInternal::stateToQString(state);
#endif
    switch (state) {
        case PA_STREAM_CREATING:
        break;
        case PA_STREAM_READY: {
#ifdef DEBUG_PULSE
            QPulseAudioInput *audioInput = static_cast<QPulseAudioInput*>(userdata);
            const pa_buffer_attr *buffer_attr = pa_stream_get_buffer_attr(stream);
            qDebug() << "*** maxlength: " << buffer_attr->maxlength;
            qDebug() << "*** prebuf: " << buffer_attr->prebuf;
            qDebug() << "*** fragsize: " << buffer_attr->fragsize;
            qDebug() << "*** minreq: " << buffer_attr->minreq;
            qDebug() << "*** tlength: " << buffer_attr->tlength;

            pa_sample_spec spec = QPulseAudioInternal::audioFormatToSampleSpec(audioInput->format());
            qDebug() << "*** bytes_to_usec: " << pa_bytes_to_usec(buffer_attr->fragsize, &spec);
#endif
            }
            break;
        case PA_STREAM_TERMINATED:
            break;
        case PA_STREAM_FAILED:
        default:
            qWarning() << QString("Stream error: %1").arg(pa_strerror(pa_context_errno(pa_stream_get_context(stream))));
            QPulseAudioEngine *pulseEngine = QPulseAudioEngine::instance();
            pa_threaded_mainloop_signal(pulseEngine->mainloop(), 0);
            break;
    }
}
示例#3
0
static void
rdpsnd_pulse_stream_state_callback(pa_stream * stream, void * userdata)
{
	rdpsndDevicePlugin * devplugin;
	struct pulse_device_data * pulse_data;
	pa_stream_state_t state;

	devplugin = (rdpsndDevicePlugin *) userdata;
	pulse_data = (struct pulse_device_data *) devplugin->device_data;
	state = pa_stream_get_state(stream);
	switch (state)
	{
		case PA_STREAM_READY:
			LLOGLN(10, ("rdpsnd_pulse_stream_state_callback: PA_STREAM_READY"));
			pa_threaded_mainloop_signal (pulse_data->mainloop, 0);
			break;

		case PA_STREAM_FAILED:
		case PA_STREAM_TERMINATED:
			LLOGLN(10, ("rdpsnd_pulse_stream_state_callback: state %d", (int)state));
			pa_threaded_mainloop_signal (pulse_data->mainloop, 0);
			break;

		default:
			LLOGLN(10, ("rdpsnd_pulse_stream_state_callback: state %d", (int)state));
			break;
	}
}
/*
 * Stream state callbacks
 *
 * A 'stream' represents a data path between the client and server.
 * Sample streams include a playback stream, a recording stream, or
 * a file upload stream.
 *
 * A single client-server connection ('context') can have multiple
 * streams. Each stream can have its own latency and time fragment
 * requirements through PulseAudio buffer attributes. A stream can
 * be moved to a different sink during its lifetime.
 */
static void stream_state_callback(pa_stream *stream, void *userdata) {
    struct context *ctx = userdata;

    assert(ctx);
    assert(ctx->context);

    switch (pa_stream_get_state(stream)) {
    case PA_STREAM_CREATING:
    case PA_STREAM_TERMINATED:
        break;

    case PA_STREAM_READY:
        out("Playback stream succesfully created");
        break;

    case PA_STREAM_FAILED:
    default:
        error("Playback stream error: %s",
              pa_strerror(pa_context_errno(ctx->context)));
        goto fail;
    }

    return;

fail:
    quit(ctx, EXIT_FAILURE);
}
float AudioDriverPulseAudio::get_latency() {

	if (latency == 0) { //only do this once since it's approximate anyway
		lock();

		pa_usec_t palat = 0;
		if (pa_stream_get_state(pa_str) == PA_STREAM_READY) {
			int negative = 0;

			if (pa_stream_get_latency(pa_str, &palat, &negative) >= 0) {
				if (negative) {
					palat = 0;
				}
			}
		}

		if (palat > 0) {
			latency = double(palat) / 1000000.0;
		}

		unlock();
	}

	return latency;
}
示例#6
0
bool AudioStream::isReady()
{
    if (!audiostream_)
        return false;

    return pa_stream_get_state(audiostream_) == PA_STREAM_READY;
}
void AudioSinksManager::InternalAudioSink::stream_state_change_callback(pa_stream* /*stream*/,
                                                                        void* userdata) {
    AudioSinksManager::InternalAudioSink* sink =
            static_cast<AudioSinksManager::InternalAudioSink*>(userdata);
    pa_stream_state_t state = pa_stream_get_state(sink->stream);
    const char* state_str = "Wrong impossible state";
    switch (state) {
        case PA_STREAM_UNCONNECTED: state_str = "UNCONNECTED"; break;
        case PA_STREAM_CREATING: state_str = "CREATING"; break;
        case PA_STREAM_READY: state_str = "READY"; break;
        case PA_STREAM_FAILED: state_str = "FAILED"; break;
        case PA_STREAM_TERMINATED: state_str = "TERMINATED"; break;
    }
    sink->manager->logger->trace("(AudioSink '{}') Stream new state: {}", sink->name, state_str);

    switch (state) {
        case PA_STREAM_FAILED:
            sink->manager->logger->error("(AudioSink '{}') Stream failed: {}", sink->name,
                                         sink->manager->get_pa_error());
            sink->state = State::DEAD;
        // FALLTHROUGH
        case PA_STREAM_TERMINATED:
            pa_stream_unref(sink->stream);
            sink->stream = nullptr;
            sink->stop_sink();
            break;
        default: break;
    }
}
int AudioOutputPulseAudio::GetBufferedOnSoundcard(void) const
{
    pa_usec_t latency = 0;
    size_t buffered = 0;

    if (!pcontext || pa_context_get_state(pcontext) != PA_CONTEXT_READY)
        return 0;

    if (!pstream || pa_stream_get_state(pstream) != PA_STREAM_READY)
        return 0;

    const pa_buffer_attr *buf_attr =  pa_stream_get_buffer_attr(pstream);
    size_t bfree = pa_stream_writable_size(pstream);
    buffered = buf_attr->tlength - bfree;

    pa_threaded_mainloop_lock(mainloop);

    while (pa_stream_get_latency(pstream, &latency, NULL) < 0)
    {
        if (pa_context_errno(pcontext) != PA_ERR_NODATA)
        {
            latency = 0;
            break;
        }
        pa_threaded_mainloop_wait(mainloop);
    }

    pa_threaded_mainloop_unlock(mainloop);

    return ((uint64_t)latency * samplerate *
            output_bytes_per_frame / 1000000) + buffered;
}
示例#9
0
static void
tsmf_pulse_stream_state_callback(pa_stream * stream, void * userdata)
{
	TSMFPulseAudioDevice * pulse = (TSMFPulseAudioDevice *) userdata;
	pa_stream_state_t state;

	state = pa_stream_get_state(stream);
	switch (state)
	{
		case PA_STREAM_READY:
			LLOGLN(10, ("tsmf_pulse_stream_state_callback: PA_STREAM_READY"));
			pa_threaded_mainloop_signal (pulse->mainloop, 0);
			break;

		case PA_STREAM_FAILED:
		case PA_STREAM_TERMINATED:
			LLOGLN(10, ("tsmf_pulse_stream_state_callback: state %d", (int)state));
			pa_threaded_mainloop_signal (pulse->mainloop, 0);
			break;

		default:
			LLOGLN(10, ("tsmf_pulse_stream_state_callback: state %d", (int)state));
			break;
	}
}
示例#10
0
void
AudioStream::stream_state_callback(pa_stream* s, void* /*user_data*/)
{
    char str[PA_SAMPLE_SPEC_SNPRINT_MAX];

    switch (pa_stream_get_state(s)) {
        case PA_STREAM_CREATING:
            DEBUG("Stream is creating...");
            break;

        case PA_STREAM_TERMINATED:
            DEBUG("Stream is terminating...");
            break;

        case PA_STREAM_READY:
            DEBUG("Stream successfully created, connected to %s", pa_stream_get_device_name(s));
            DEBUG("maxlength %u", pa_stream_get_buffer_attr(s)->maxlength);
            DEBUG("tlength %u", pa_stream_get_buffer_attr(s)->tlength);
            DEBUG("prebuf %u", pa_stream_get_buffer_attr(s)->prebuf);
            DEBUG("minreq %u", pa_stream_get_buffer_attr(s)->minreq);
            DEBUG("fragsize %u", pa_stream_get_buffer_attr(s)->fragsize);
            DEBUG("samplespec %s", pa_sample_spec_snprint(str, sizeof(str), pa_stream_get_sample_spec(s)));
            break;

        case PA_STREAM_UNCONNECTED:
            DEBUG("Stream unconnected");
            break;

        case PA_STREAM_FAILED:
        default:
            ERROR("Sink/Source doesn't exists: %s" , pa_strerror(pa_context_errno(pa_stream_get_context(s))));
            break;
    }
}
示例#11
0
/** Play the specified data to the polypaudio server */
static int play(void* data, int len, int flags) {
    assert(stream && context);

    if (pa_stream_get_state(stream) != PA_STREAM_READY)
        return -1;

    if (!len)
        wait_for_operation(pa_stream_trigger(stream, NULL, NULL));
    else
        pa_stream_write(stream, data, len, NULL, 0);

    wait_for_completion();

    if (pa_stream_get_state(stream) != PA_STREAM_READY)
        return -1;

    return len;
}
static void stream_state_cb(pa_stream *s, void *userdata) {
    switch (pa_stream_get_state(s)) {
        case PA_STREAM_READY:
        case PA_STREAM_FAILED:
        case PA_STREAM_TERMINATED:
            pa_threaded_mainloop_signal(mainloop, 0);
            break;
    }
}
void AudioOutputPulseAudio::WriteAudio(uchar *aubuf, int size)
{
    QString fn_log_tag = "WriteAudio, ";
    pa_stream_state_t sstate = pa_stream_get_state(pstream);

    VBAUDIOTS(fn_log_tag + QString("writing %1 bytes").arg(size));

    /* NB This "if" check can be replaced with PA_STREAM_IS_GOOD() in
       PulseAudio API from 0.9.11. As 0.9.10 is still widely used
       we use the more verbose version for now */

    if (sstate == PA_STREAM_CREATING || sstate == PA_STREAM_READY)
    {
        int write_status = PA_ERR_INVALID;
        size_t to_write = size;
        unsigned char *buf_ptr = aubuf;

        pa_threaded_mainloop_lock(mainloop);
        while (to_write > 0)
        {
            write_status = 0;
            size_t writable = pa_stream_writable_size(pstream);
            if (writable > 0)
            {
                size_t write = min(to_write, writable);
                write_status = pa_stream_write(pstream, buf_ptr, write,
                                               NULL, 0, PA_SEEK_RELATIVE);

                if (0 != write_status)
                    break;

                buf_ptr += write;
                to_write -= write;
            }
            else
            {
                pa_threaded_mainloop_wait(mainloop);
            }
        }
        pa_threaded_mainloop_unlock(mainloop);

        if (to_write > 0)
        {
            if (write_status != 0)
                VBERROR(fn_log_tag + QString("stream write failed: %1")
                                     .arg(write_status == PA_ERR_BADSTATE
                                                ? "PA_ERR_BADSTATE"
                                                : "PA_ERR_INVALID"));

            VBERROR(fn_log_tag + QString("short write, %1 of %2")
                                 .arg(size - to_write).arg(size));
        }
    }
    else
        VBERROR(fn_log_tag + QString("stream state not good: %1")
                             .arg(sstate,0,16));
}
示例#14
0
// PulseAudio Event Callbacks //{{{
static void stream_state_callback(pa_stream *stream, void *pdata) //{{{
{
    pa_threaded_mainloop *loop = pdata;
    pa_stream_state_t state;

    state = pa_stream_get_state(stream);
    if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state))
        pa_threaded_mainloop_signal(loop, 0);
}//}}}
示例#15
0
/** Return number of bytes that may be written to the server without blocking */
static int get_space(void) {
    uint32_t l;
    assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);
    
    keep_alive();

    l = pa_stream_writable_size(stream);
    
    return l;
}
/**
 * Pulseaudio stream state callback
 */
static void
stream_state_callback (pa_stream * s, void *userdata)
{
  GNUNET_assert (NULL != s);

  switch (pa_stream_get_state (s))
  {
  case PA_STREAM_CREATING:
  case PA_STREAM_TERMINATED:
    break;
  case PA_STREAM_READY:
    {
      const pa_buffer_attr *a;
      char cmt[PA_CHANNEL_MAP_SNPRINT_MAX];
      char sst[PA_SAMPLE_SPEC_SNPRINT_MAX];

      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
		  _("Stream successfully created.\n"));

      if (!(a = pa_stream_get_buffer_attr (s)))
      {
	GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		    _("pa_stream_get_buffer_attr() failed: %s\n"),
		    pa_strerror (pa_context_errno
				 (pa_stream_get_context (s))));

      }
      else
      {
	GNUNET_log (GNUNET_ERROR_TYPE_INFO,
		    _("Buffer metrics: maxlength=%u, fragsize=%u\n"),
		    a->maxlength, a->fragsize);
      }
      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
		  _("Using sample spec '%s', channel map '%s'.\n"),
		  pa_sample_spec_snprint (sst, sizeof (sst),
					  pa_stream_get_sample_spec (s)),
		  pa_channel_map_snprint (cmt, sizeof (cmt),
					  pa_stream_get_channel_map (s)));

      GNUNET_log (GNUNET_ERROR_TYPE_INFO,
		  _("Connected to device %s (%u, %ssuspended).\n"),
		  pa_stream_get_device_name (s),
		  pa_stream_get_device_index (s),
		  pa_stream_is_suspended (s) ? "" : "not ");
    }
    break;
  case PA_STREAM_FAILED:
  default:
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
		_("Stream error: %s\n"),
		pa_strerror (pa_context_errno (pa_stream_get_context (s))));
    quit (1);
  }
}
示例#17
0
static ALCenum pulse_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples)
{
    pulse_data *data = device->ExtraData;
    ALCuint todo = samples * pa_frame_size(&data->spec);

    pa_threaded_mainloop_lock(data->loop);
    /* Capture is done in fragment-sized chunks, so we loop until we get all
     * that's available */
    data->last_readable -= todo;
    while(todo > 0)
    {
        size_t rem = todo;

        if(data->cap_len == 0)
        {
            pa_stream_state_t state;

            state = pa_stream_get_state(data->stream);
            if(!PA_STREAM_IS_GOOD(state))
            {
                aluHandleDisconnect(device);
                break;
            }
            if(pa_stream_peek(data->stream, &data->cap_store, &data->cap_len) < 0)
            {
                ERR("pa_stream_peek() failed: %s\n",
                    pa_strerror(pa_context_errno(data->context)));
                aluHandleDisconnect(device);
                break;
            }
            data->cap_remain = data->cap_len;
        }
        if(rem > data->cap_remain)
            rem = data->cap_remain;

        memcpy(buffer, data->cap_store, rem);

        buffer = (ALbyte*)buffer + rem;
        todo -= rem;

        data->cap_store = (ALbyte*)data->cap_store + rem;
        data->cap_remain -= rem;
        if(data->cap_remain == 0)
        {
            pa_stream_drop(data->stream);
            data->cap_len = 0;
        }
    }
    if(todo > 0)
        memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo);
    pa_threaded_mainloop_unlock(data->loop);

    return ALC_NO_ERROR;
}
示例#18
0
static void time_event_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
    if (stream && pa_stream_get_state(stream) == PA_STREAM_READY) {
        pa_operation *o;
        if (!(o = pa_stream_update_timing_info(stream, stream_update_timing_callback, NULL)))
            pa_log(_("pa_stream_update_timing_info() failed: %s"), pa_strerror(pa_context_errno(context)));
        else
            pa_operation_unref(o);
    }

    pa_context_rttime_restart(context, e, pa_rtclock_now() + TIME_EVENT_USEC);
}
示例#19
0
void PulseAudioSystem::stream_callback(pa_stream *s, void *userdata) {
	PulseAudioSystem *pas = reinterpret_cast<PulseAudioSystem *>(userdata);
	switch (pa_stream_get_state(s)) {
		case PA_STREAM_FAILED:
			qWarning("PulseAudio: Stream error: %s", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
			break;
		default:
			break;
	}
	pas->wakeup();
}
示例#20
0
static void stream_state_callback(pa_stream *s,void*){
  fxmessage("[pulse] stream_state_callback:");
  switch(pa_stream_get_state(s)) {
    case PA_STREAM_UNCONNECTED : fxmessage(" unconnected\n"); break;
    case PA_STREAM_CREATING    : fxmessage(" creating\n"); break;
    case PA_STREAM_READY       : fxmessage(" ready\n"); break;
    case PA_STREAM_FAILED      : fxmessage(" failed\n"); break;
    case PA_STREAM_TERMINATED  : fxmessage(" terminated\n"); break;
    default                     : fxmessage(" unknown\n"); break;
    }
  }
示例#21
0
static int stream_wait(pa_stream *stream, pa_threaded_mainloop *mainloop)
{
    pa_stream_state_t state;

    while ((state = pa_stream_get_state(stream)) != PA_STREAM_READY) {
        if (state == PA_STREAM_FAILED || state == PA_STREAM_TERMINATED)
            return -1;
        pa_threaded_mainloop_wait(mainloop);
    }
    return 0;
}
示例#22
0
/** Return the current latency in seconds */
static float get_delay(void) {
    pa_usec_t latency;
    assert(stream && context && pa_stream_get_state(stream) == PA_STREAM_READY);

    /*     latency = 0; */
/*     wait_for_operation(pa_stream_get_latency(stream, latency_func, NULL)); */
    /*     pa_operation_unref(pa_stream_get_latency(stream, latency_func, NULL)); */

    latency = pa_stream_get_interpolated_latency(stream, NULL);
    
    return (float) latency/1000000;
}
示例#23
0
static void stream_state_callback2(pa_stream *stream, void *pdata) //{{{
{
    ALCdevice *Device = pdata;
    pulse_data *data = Device->ExtraData;

    if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
    {
        ERR("Received stream failure!\n");
        aluHandleDisconnect(Device);
    }
    pa_threaded_mainloop_signal(data->loop, 0);
}//}}}
示例#24
0
static void stream_state_cb(pa_stream *s, void *userdata)
{
    struct ao *ao = userdata;
    struct priv *priv = ao->priv;
    switch (pa_stream_get_state(s)) {
    case PA_STREAM_READY:
    case PA_STREAM_FAILED:
    case PA_STREAM_TERMINATED:
        pa_threaded_mainloop_signal(priv->mainloop, 0);
        break;
    }
}
示例#25
0
/*
 * Create a new pulse audio stream and connect to it
 *
 * Return a negative value on error
 */
static int pulse_connect_stream(struct pulse_data *data)
{
	pa_sample_spec spec;
	spec.format = data->format;
	spec.rate = data->samples_per_sec;
	spec.channels = get_audio_channels(data->speakers);

	if (!pa_sample_spec_valid(&spec)) {
		blog(LOG_ERROR, "pulse-input: Sample spec is not valid");
		return -1;
	}

	data->bytes_per_frame = pa_frame_size(&spec);
	blog(LOG_DEBUG, "pulse-input: %u bytes per frame",
	     (unsigned int) data->bytes_per_frame);

	pa_buffer_attr attr;
	attr.fragsize = get_buffer_size(data, 250);
	attr.maxlength = (uint32_t) -1;
	attr.minreq = (uint32_t) -1;
	attr.prebuf = (uint32_t) -1;
	attr.tlength = (uint32_t) -1;

	data->stream = pa_stream_new_with_proplist(data->context,
		obs_source_getname(data->source), &spec, NULL, data->props);
	if (!data->stream) {
		blog(LOG_ERROR, "pulse-input: Unable to create stream");
		return -1;
	}
	pa_stream_flags_t flags =
		PA_STREAM_INTERPOLATE_TIMING
		| PA_STREAM_AUTO_TIMING_UPDATE
		| PA_STREAM_ADJUST_LATENCY;
	if (pa_stream_connect_record(data->stream, NULL, &attr, flags) < 0) {
		blog(LOG_ERROR, "pulse-input: Unable to connect to stream");
		return -1;
	}

	for (;;) {
		pulse_iterate(data);
		pa_stream_state_t state = pa_stream_get_state(data->stream);
		if (state == PA_STREAM_READY) {
			blog(LOG_DEBUG, "pulse-input: Stream ready");
			break;
		}
		if (!PA_STREAM_IS_GOOD(state)) {
			blog(LOG_ERROR, "pulse-input: Stream connect failed");
			return -1;
		}
	}

	return 0;
}
示例#26
0
static void
stream_state_wait(cubeb_stream * stm, pa_stream_state_t target_state)
{
  pa_threaded_mainloop_lock(stm->context->mainloop);
  for (;;) {
    pa_stream_state_t state = pa_stream_get_state(stm->stream);
    assert(PA_CONTEXT_IS_GOOD(state));
    if (state == target_state)
      break;
    pa_threaded_mainloop_wait(stm->context->mainloop);
  }
  pa_threaded_mainloop_unlock(stm->context->mainloop);
}
示例#27
0
static void
stream_state_callback(pa_stream *s, void *userdata)
{
  pa_audio_mode_t *pam = (pa_audio_mode_t *)userdata;
  pa_operation *o;

  if(pa_stream_get_state(s) == PA_STREAM_FAILED) {
    pam->stream_error = pa_context_errno(pam->context);
    TRACE(TRACE_ERROR, "PA",
	  "Stream failure: %s", pa_strerror(pam->stream_error));
  }

  if(pa_stream_get_state(s) == PA_STREAM_READY && pam->muted) {
    o = pa_context_set_sink_input_mute(pam->context,
				       pa_stream_get_index(pam->stream),
				       pam->muted, NULL, NULL);
    if(o != NULL)
      pa_operation_unref(o);
  }

  pa_threaded_mainloop_signal(mainloop, 0);
}
示例#28
0
/**
 * Check if the stream is (already) connected, and waits for a signal
 * if not.  The mainloop must be locked before calling this function.
 *
 * @return the current stream state
 */
static pa_stream_state_t
pulse_output_check_stream(struct pulse_output *po)
{
	pa_stream_state_t state = pa_stream_get_state(po->stream);

	assert(po->mainloop != NULL);

	switch (state) {
	case PA_STREAM_READY:
	case PA_STREAM_FAILED:
	case PA_STREAM_TERMINATED:
	case PA_STREAM_UNCONNECTED:
		break;

	case PA_STREAM_CREATING:
		pa_threaded_mainloop_wait(po->mainloop);
		state = pa_stream_get_state(po->stream);
		break;
	}

	return state;
}
示例#29
0
文件: oss.cpp 项目: dreiss/M1-Android
void m1sdr_PlayStop(void)
{
	#if 0
	pa_operation *op;
	#endif

	#ifdef USE_SDL
	if (lnxdrv_apimode == 0) 
	{
		SDL_PauseAudio(1);
	}
	#endif

	if (lnxdrv_apimode == 1)
	{
//		snd_pcm_pause(pHandle, 1);
		snd_pcm_drop(pHandle);
	}

	#if PULSE_USE_SIMPLE
	if ((lnxdrv_apimode == 3) && (my_simple))
	{
		pa_simple_flush(my_simple, NULL);
		pa_simple_free(my_simple);
		my_simple = NULL;
	}
	#else
#if 0
	if (lnxdrv_apimode == 3)
	{
		op = pa_stream_drain(my_pa_stream, &pa_stream_drain_complete, NULL);
		if (op)
		{
			while (pa_operation_get_state(op) != PA_OPERATION_DONE)
			{
				if (pa_context_get_state(my_pa_context) != PA_CONTEXT_READY ||
				    pa_stream_get_state(my_pa_stream) != PA_STREAM_READY ||
				    pa_mainloop_iterate(my_pa_mainloop, 0, NULL) < 0)
				    {
				    	pa_operation_cancel(op);
					break;
				    }
			}
		}
	}
#endif
	#endif

	waveLogStop();
	oss_playing = 0;
}
static void stream_state_callback(pa_stream *stream, void *userdata) {
  sa_stream_t* s = (sa_stream_t*)userdata;
  switch (pa_stream_get_state(stream)) {

      case PA_STREAM_READY:
      case PA_STREAM_FAILED:
      case PA_STREAM_TERMINATED:
        pa_threaded_mainloop_signal(s->m, 0);
        break;
      case PA_STREAM_UNCONNECTED:
      case PA_STREAM_CREATING:
        break;
  }
}