Пример #1
0
static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
{
    PAVoiceIn *pa = (PAVoiceIn *) hw;
    pa_operation *op;
    pa_cvolume v;
    paaudio *g = pa->g;

#ifdef PA_CHECK_VERSION
    pa_cvolume_init (&v);
#endif

    switch (cmd) {
    case VOICE_VOLUME:
        {
            SWVoiceIn *sw;
            va_list ap;

            va_start (ap, cmd);
            sw = va_arg (ap, SWVoiceIn *);
            va_end (ap);

            v.channels = 2;
            v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
            v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;

            pa_threaded_mainloop_lock (g->mainloop);

            op = pa_context_set_source_output_volume (g->context,
                pa_stream_get_index (pa->stream),
                &v, NULL, NULL);
            if (!op) {
                qpa_logerr (pa_context_errno (g->context),
                            "set_source_output_volume() failed\n");
            } else {
                pa_operation_unref(op);
            }

            op = pa_context_set_source_output_mute (g->context,
                pa_stream_get_index (pa->stream),
                sw->vol.mute, NULL, NULL);
            if (!op) {
                qpa_logerr (pa_context_errno (g->context),
                            "set_source_output_mute() failed\n");
            } else {
                pa_operation_unref (op);
            }

            pa_threaded_mainloop_unlock (g->mainloop);
        }
    }
    return 0;
}
static int control(int cmd, void *arg) {
    switch (cmd) {
        case AOCONTROL_GET_VOLUME: {
            ao_control_vol_t *vol = arg;
            uint32_t devidx = pa_stream_get_index(stream);
            pa_threaded_mainloop_lock(mainloop);
            if (!waitop(pa_context_get_sink_input_info(context, devidx, info_func, NULL))) {
                GENERIC_ERR_MSG(context, "pa_stream_get_sink_input_info() failed");
                return CONTROL_ERROR;
            }

            if (volume.channels != 2)
                vol->left = vol->right = pa_cvolume_avg(&volume)*100/PA_VOLUME_NORM;
            else {
                vol->left = volume.values[0]*100/PA_VOLUME_NORM;
                vol->right = volume.values[1]*100/PA_VOLUME_NORM;
            }

            return CONTROL_OK;
        }

        case AOCONTROL_SET_VOLUME: {
            const ao_control_vol_t *vol = arg;
            pa_operation *o;

            if (volume.channels != 2)
                pa_cvolume_set(&volume, volume.channels, (pa_volume_t)vol->left*PA_VOLUME_NORM/100);
            else {
                volume.values[0] = (pa_volume_t)vol->left*PA_VOLUME_NORM/100;
                volume.values[1] = (pa_volume_t)vol->right*PA_VOLUME_NORM/100;
            }

            pa_threaded_mainloop_lock(mainloop);
            o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL);
            if (!o) {
                pa_threaded_mainloop_unlock(mainloop);
                GENERIC_ERR_MSG(context, "pa_context_set_sink_input_volume() failed");
                return CONTROL_ERROR;
            }
            /* We don't wait for completion here */
            pa_operation_unref(o);
            pa_threaded_mainloop_unlock(mainloop);
            return CONTROL_OK;
        }

        default:
            return CONTROL_UNKNOWN;
    }
}
Пример #3
0
void CPulseAEStream::SetVolume(float volume)
{
  if (!m_Initialized)
    return;

  if (!pa_threaded_mainloop_in_thread(m_MainLoop))
    pa_threaded_mainloop_lock(m_MainLoop);

  if (volume > 0.f)
  {
    m_Volume = volume;
    pa_volume_t paVolume = pa_sw_volume_from_linear((double)(m_Volume * m_MaxVolume));

    pa_cvolume_set(&m_ChVolume, m_SampleSpec.channels, paVolume);
  } 
  else
    pa_cvolume_mute(&m_ChVolume,m_SampleSpec.channels);

  pa_operation *op = pa_context_set_sink_input_volume(m_Context, pa_stream_get_index(m_Stream), &m_ChVolume, NULL, NULL);

  if (op == NULL)
    CLog::Log(LOGERROR, "PulseAudio: Failed to set volume");
  else
    pa_operation_unref(op);

  if (!pa_threaded_mainloop_in_thread(m_MainLoop))
    pa_threaded_mainloop_unlock(m_MainLoop);
}
Пример #4
0
int xmms_pulse_backend_volume_get (xmms_pulse *p, unsigned int *vol)
{
	pa_operation *o;
	int idx;

	if (p == NULL) {
		return FALSE;
	}

	pa_threaded_mainloop_lock (p->mainloop);

	*vol = -1;

	if (p->stream != NULL) {
		idx = pa_stream_get_index (p->stream);

		o = pa_context_get_sink_input_info (p->context, idx,
		                                    volume_get_cb, vol);

		if (o) {
			while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
				pa_threaded_mainloop_wait (p->mainloop);
			}

			pa_operation_unref (o);
		}
	}

	pa_threaded_mainloop_unlock (p->mainloop);

	return *vol != -1;
}
Пример #5
0
/**
 * @brief Callback function called when the state of the daemon changes
 * @param c Context in which the state of the daemon changes
 * @param t Subscription event type
 * @param idx Index of the sink
 * @param this_gen pulse_driver_t pointer for the PulseAudio output
 *        instance.
 */
static void __xine_pa_context_subscribe_callback(pa_context *c,
    pa_subscription_event_type_t t, uint32_t idx, void *this_gen)
{
  pulse_driver_t * this = (pulse_driver_t*) this_gen;
  int index;

  if (this->stream == NULL)
    return;

  index = pa_stream_get_index(this->stream);

  if (index != idx)
    return;

  if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
    return;

  pa_operation *operation = pa_context_get_sink_input_info(
      this->context, index, __xine_pa_sink_info_callback, this);

  if (operation == NULL) {
    xprintf(this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: failed to get sink info: %s\n", pa_strerror(pa_context_errno (this->context)));
    return;
  }

  pa_operation_unref(operation);
}
Пример #6
0
bool
pulse_output_set_volume(struct pulse_output *po,
			const struct pa_cvolume *volume, GError **error_r)
{
	pa_operation *o;

	if (po->context == NULL || po->stream == NULL ||
	    pa_stream_get_state(po->stream) != PA_STREAM_READY) {
		g_set_error(error_r, pulse_output_quark(), 0, "disconnected");
		return false;
	}

	o = pa_context_set_sink_input_volume(po->context,
					     pa_stream_get_index(po->stream),
					     volume, NULL, NULL);
	if (o == NULL) {
		g_set_error(error_r, pulse_output_quark(), 0,
			    "failed to set PulseAudio volume: %s",
			    pa_strerror(pa_context_errno(po->context)));
		return false;
	}

	pa_operation_unref(o);
	return true;
}
Пример #7
0
void PulseOutput::volume(FXfloat v) {
  if (pulse_context && stream) {
    pulsevolume = (pa_volume_t)(v*PA_VOLUME_NORM);
    pa_cvolume cvol;
    pa_cvolume_set(&cvol,af.channels,pulsevolume);
    pa_operation* operation = pa_context_set_sink_input_volume(pulse_context,pa_stream_get_index(stream),&cvol,nullptr,nullptr);
    pa_operation_unref(operation);
    }
  }
Пример #8
0
/** Issue special libao controls on the device */
static int control(int cmd, void *arg) {
    
    if (!context || !stream)
        return CONTROL_ERROR;
    
    switch (cmd) {

        case AOCONTROL_SET_DEVICE:
            /* Change the playback device */
            sink = (char*)arg;
            return CONTROL_OK;

        case AOCONTROL_GET_DEVICE:
            /* Return the playback device */
            *(char**)arg = sink;
            return CONTROL_OK;
        
        case AOCONTROL_GET_VOLUME: {
            /* Return the current volume of the playback stream */
            ao_control_vol_t *vol = (ao_control_vol_t*) arg;
                
            volume = PA_VOLUME_NORM;
            wait_for_operation(pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_func, NULL));
            vol->left = vol->right = (int) (pa_volume_to_user(volume)*100);
            return CONTROL_OK;
        }
            
        case AOCONTROL_SET_VOLUME: {
            /* Set the playback volume of the stream */
            const ao_control_vol_t *vol = (ao_control_vol_t*) arg;
            int v = vol->left;
            if (vol->right > v)
                v = vol->left;
            
            wait_for_operation(pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), pa_volume_from_user((double)v/100), NULL, NULL));
            
            return CONTROL_OK;
        }
            
        default:
            /* Unknown CONTROL command */
            return CONTROL_UNKNOWN;
    }
}
void AudioOutputPulseAudio::SetVolumeChannel(int channel, int volume)
{
    QString fn_log_tag = "SetVolumeChannel, ";

    if (channel < 0 || channel > PULSE_MAX_CHANNELS || volume < 0)
    {
        VBERROR(fn_log_tag + QString("bad volume params, channel %1, volume %2")
                             .arg(channel).arg(volume));
        return;
    }

    volume_control.values[channel] =
        (float)volume / 100.0f * (float)PA_VOLUME_NORM;

    volume = min(100, volume);
    volume = max(0, volume);

    if (gCoreContext->GetSetting("MixerControl", "PCM").toLower() == "pcm")
    {
        uint32_t stream_index = pa_stream_get_index(pstream);
        pa_threaded_mainloop_lock(mainloop);
        pa_operation *op =
            pa_context_set_sink_input_volume(pcontext, stream_index,
                                             &volume_control,
                                             OpCompletionCallback, this);
        pa_threaded_mainloop_unlock(mainloop);
        if (op)
            pa_operation_unref(op);
        else
            VBERROR(fn_log_tag +
                    QString("set stream volume operation failed, stream %1, "
                            "error %2 ")
                    .arg(stream_index)
                    .arg(pa_strerror(pa_context_errno(pcontext))));
    }
    else
    {
        uint32_t sink_index = pa_stream_get_device_index(pstream);
        pa_threaded_mainloop_lock(mainloop);
        pa_operation *op =
            pa_context_set_sink_volume_by_index(pcontext, sink_index,
                                                &volume_control,
                                                OpCompletionCallback, this);
        pa_threaded_mainloop_unlock(mainloop);
        if (op)
            pa_operation_unref(op);
        else
            VBERROR(fn_log_tag +
                    QString("set sink volume operation failed, sink %1, "
                            "error %2 ")
                    .arg(sink_index)
                    .arg(pa_strerror(pa_context_errno(pcontext))));
    }
}
Пример #10
0
static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) {
  ENTER(__FUNCTION__);
    
    assert(c);

    if (!stream ||
        index != pa_stream_get_index(stream) ||
        (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
         t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)))
        return;
}
Пример #11
0
static void volume_time_cb(pa_mainloop_api *api, pa_time_event *e, const struct timeval *tv, void *userdata) {
    pa_operation *o;

    if (!(o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL)))
        AUDDBG("pa_context_set_sink_input_volume() failed: %s", pa_strerror(pa_context_errno(context)));
    else
        pa_operation_unref(o);

    /* We don't wait for completion of this command */

    api->time_free(volume_time_event);
    volume_time_event = NULL;
}
Пример #12
0
static void SinkInputInfoChangedCallback(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata)
{
  CAESinkPULSE* p = (CAESinkPULSE*) userdata;
  if (!p || !p->IsInitialized())
    return;
  
   if (idx != pa_stream_get_index(p->GetInternalStream()))
     return;
   
   pa_operation* op = pa_context_get_sink_input_info(c, idx, SinkInputInfoCallback, p);
   if (op == NULL)
     CLog::Log(LOGERROR, "PulseAudio: Failed to sync volume");
   else
    pa_operation_unref(op);
}
int pa_simple_set_volume(pa_simple *p, int volume, int *rerror) {
    pa_operation *o = NULL;
    pa_stream *s = NULL;
    uint32_t idx;
    pa_cvolume cv;
    pa_volume_t v;

    pa_assert(p);

    CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
    CHECK_VALIDITY_RETURN_ANY(rerror, volume >= 0, PA_ERR_INVALID, -1);
    CHECK_VALIDITY_RETURN_ANY(rerror, volume <= 65535, PA_ERR_INVALID, -1);

    pa_threaded_mainloop_lock(p->mainloop);
    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);

    CHECK_SUCCESS_GOTO(p, rerror, ((idx = pa_stream_get_index (p->stream)) != PA_INVALID_INDEX), unlock_and_fail);

    s = p->stream;
    pa_assert(s);
    pa_cvolume_set(&cv, s->sample_spec.channels, volume);

    o = pa_context_set_sink_input_volume (p->context, idx, &cv, success_context_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;
}
int pa_simple_get_stream_index(pa_simple *p, unsigned int *idx, int *rerror) {
    pa_assert(p);
    CHECK_VALIDITY_RETURN_ANY(rerror, idx != NULL, PA_ERR_INVALID, -1);

    pa_threaded_mainloop_lock(p->mainloop);

    CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);

	*idx = pa_stream_get_index(p->stream);

    pa_threaded_mainloop_unlock(p->mainloop);
    return 0;

unlock_and_fail:
    pa_threaded_mainloop_unlock(p->mainloop);
    return -1;
}
Пример #15
0
static void subscribe_cb(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata) {
    pa_operation *o;

    assert(c);

    if (!stream ||
        index != pa_stream_get_index(stream) ||
        (t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) &&
         t != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW)))
        return;

    if (!(o = pa_context_get_sink_input_info(c, index, info_cb, NULL))) {
        AUDDBG("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(c)));
        return;
    }

    pa_operation_unref(o);
}
Пример #16
0
/**
 * Mute (from within showtime), send update to PA
 *
 * Lock for PA mainloop is already held
 */
static void
set_mastermute(void *opaque, int value)
{
  pa_audio_mode_t *pam = opaque;
  pa_operation *o;

  pam->muted = value;

  if(pam->stream == NULL ||
     pa_stream_get_state(pam->stream) != PA_STREAM_READY)
    return;

  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);
}
Пример #17
0
void PulseOutput::context_subscribe_callback(pa_context * pulse_context, pa_subscription_event_type_t type, uint32_t index, void *userdata){
  PulseOutput * out = static_cast<PulseOutput*>(userdata);

  if (out->stream==nullptr)
    return;

  if (pa_stream_get_index(out->stream)!=index)
    return;

  if ((type&PA_SUBSCRIPTION_EVENT_FACILITY_MASK)!=PA_SUBSCRIPTION_EVENT_SINK_INPUT)
    return;

  if ((type&PA_SUBSCRIPTION_EVENT_TYPE_MASK)==PA_SUBSCRIPTION_EVENT_CHANGE ||
      (type&PA_SUBSCRIPTION_EVENT_TYPE_MASK)==PA_SUBSCRIPTION_EVENT_NEW) {
    pa_operation *operation = pa_context_get_sink_input_info(pulse_context,index,sink_info_callback,userdata);
    if (operation) pa_operation_unref(operation);
    }
  }
Пример #18
0
static void
pulse_output_subscribe_cb(pa_context *context,
			  pa_subscription_event_type_t t,
			  uint32_t idx, void *userdata)
{
	struct pulse_output *po = userdata;
	pa_subscription_event_type_t facility
		= t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;
	pa_subscription_event_type_t type
		= t & PA_SUBSCRIPTION_EVENT_TYPE_MASK;

	if (po->mixer != NULL &&
	    facility == PA_SUBSCRIPTION_EVENT_SINK_INPUT &&
	    po->stream != NULL &&
	    pa_stream_get_state(po->stream) == PA_STREAM_READY &&
	    idx == pa_stream_get_index(po->stream) &&
	    (type == PA_SUBSCRIPTION_EVENT_NEW ||
	     type == PA_SUBSCRIPTION_EVENT_CHANGE))
		pulse_mixer_on_change(po->mixer, context, po->stream);
}
Пример #19
0
int xmms_pulse_backend_volume_set (xmms_pulse *p, unsigned int vol)
{
	pa_operation *o;
	pa_cvolume cvol;
	int idx, res = 0;

	if (p == NULL) {
		return FALSE;
	}

	pa_threaded_mainloop_lock (p->mainloop);

	if (p->stream != NULL) {
		pa_cvolume_set (&cvol, p->sample_spec.channels,
		                PA_VOLUME_NORM * vol / 100);

		idx = pa_stream_get_index (p->stream);

		o = pa_context_set_sink_input_volume (p->context, idx, &cvol,
		                                      volume_set_cb, &res);
		if (o) {
			/* wait for result to land */
			while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
				pa_threaded_mainloop_wait (p->mainloop);
			}

			pa_operation_unref (o);

			/* The cb set res to 1 or 0 depending on success */
			if (res) {
				p->volume = vol;
			}
		}

	}

	pa_threaded_mainloop_unlock (p->mainloop);

	return res;
}
Пример #20
0
/**
 * Volume adjusted (from within showtime), send update to PA
 *
 * Lock for PA mainloop is already held
 */
static void
set_mastervol(void *opaque, float value)
{
  pa_audio_mode_t *pam = opaque;
  pa_operation *o;
  pa_cvolume cv;

  pam->mastervol = pa_sw_volume_from_dB(value);

  if(pam->stream == NULL ||
     pa_stream_get_state(pam->stream) != PA_STREAM_READY)
    return;
  
  memset(&cv, 0, sizeof(cv));
  pa_cvolume_set(&cv, pam->ss.channels, pam->mastervol);

  o = pa_context_set_sink_input_volume(pam->context, 
				       pa_stream_get_index(pam->stream),
				       &cv, NULL, NULL);
  if(o != NULL)
    pa_operation_unref(o);
}
Пример #21
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);
}
Пример #22
0
static void
subscription_event_callback(pa_context *c, pa_subscription_event_type_t t,
			    uint32_t idx, void *userdata)
{
  pa_audio_mode_t *pam = (pa_audio_mode_t *)userdata;
  pa_operation *o;

  if(pam->stream == NULL ||
     pa_stream_get_state(pam->stream) != PA_STREAM_READY)
    return;

  if((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) !=
     PA_SUBSCRIPTION_EVENT_SINK_INPUT)
    return;

  if(pa_stream_get_index(pam->stream) != idx)
    return;

  o = pa_context_get_sink_input_info(pam->context, idx,
				     update_sink_input_info, pam);
  if(o != NULL)
    pa_operation_unref(o);
}
Пример #23
0
void CAESinkPULSE::SetVolume(float volume)
{
  if (m_IsAllocated && !m_passthrough)
  {
    pa_threaded_mainloop_lock(m_MainLoop);
    // clamp possibly too large / low values
    float per_cent_volume = std::max(0.0f, std::min(volume, 1.0f));
    
    if (m_volume_needs_update)
    {
       m_volume_needs_update = false;
       pa_volume_t n_vol = pa_cvolume_avg(&m_Volume); 
       n_vol = std::min(n_vol, PA_VOLUME_NORM);
       per_cent_volume = (float) n_vol / PA_VOLUME_NORM; 
       // only update internal volume
       pa_threaded_mainloop_unlock(m_MainLoop);
       g_application.SetVolume(per_cent_volume, false);
       return;
    }
    
    pa_volume_t pavolume = per_cent_volume * PA_VOLUME_NORM;
    unsigned int sink_input_idx = pa_stream_get_index(m_Stream);
    
    if ( pavolume <= 0 )
      pa_cvolume_mute(&m_Volume, m_Channels);
    else
      pa_cvolume_set(&m_Volume, m_Channels, pavolume);
        
      pa_operation *op = pa_context_set_sink_input_volume(m_Context, sink_input_idx, &m_Volume, NULL, NULL);
      if (op == NULL)
        CLog::Log(LOGERROR, "PulseAudio: Failed to set volume");
      else
        pa_operation_unref(op);

    pa_threaded_mainloop_unlock(m_MainLoop);
  }
}
Пример #24
0
/*** Context ***/
static void context_cb(pa_context *ctx, pa_subscription_event_type_t type,
                       uint32_t idx, void *userdata)
{
    audio_output_t *aout = userdata;
    aout_sys_t *sys = aout->sys;
    unsigned facility = type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK;

    type &= PA_SUBSCRIPTION_EVENT_TYPE_MASK;
    switch (facility)
    {
        case PA_SUBSCRIPTION_EVENT_SINK:
            sink_event(ctx, type, idx, userdata);
            break;

        case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
            /* only interested in our sink input */
            if (sys->stream != NULL && idx == pa_stream_get_index(sys->stream))
                sink_input_event(ctx, type, idx, userdata);
            break;

        default: /* unsubscribed facility?! */
            assert(0);
    }
}
Пример #25
0
void AudioStream::moved(pa_stream* s)
{
    audiostream_ = s;
    RING_DBG("Stream %d to %s", pa_stream_get_index(s), pa_stream_get_device_name(s));
}
Пример #26
0
static gboolean
gst_pulsesrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
{
  pa_buffer_attr wanted;
  const pa_buffer_attr *actual;
  GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
  pa_stream_flags_t flags;
  pa_operation *o;
  GstAudioClock *clock;

  pa_threaded_mainloop_lock (pulsesrc->mainloop);

  {
    GstAudioRingBufferSpec s = *spec;
    const pa_channel_map *m;

    m = pa_stream_get_channel_map (pulsesrc->stream);
    gst_pulse_channel_map_to_gst (m, &s);
    gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC
        (pulsesrc)->ringbuffer, s.info.position);
  }

  /* enable event notifications */
  GST_LOG_OBJECT (pulsesrc, "subscribing to context events");
  if (!(o = pa_context_subscribe (pulsesrc->context,
              PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, NULL, NULL))) {
    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
        ("pa_context_subscribe() failed: %s",
            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
    goto unlock_and_fail;
  }

  pa_operation_unref (o);

  wanted.maxlength = -1;
  wanted.tlength = -1;
  wanted.prebuf = 0;
  wanted.minreq = -1;
  wanted.fragsize = spec->segsize;

  GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength);
  GST_INFO_OBJECT (pulsesrc, "tlength:   %d", wanted.tlength);
  GST_INFO_OBJECT (pulsesrc, "prebuf:    %d", wanted.prebuf);
  GST_INFO_OBJECT (pulsesrc, "minreq:    %d", wanted.minreq);
  GST_INFO_OBJECT (pulsesrc, "fragsize:  %d", wanted.fragsize);

  flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
      PA_STREAM_NOT_MONOTONIC | PA_STREAM_ADJUST_LATENCY |
      PA_STREAM_START_CORKED;

  if (pulsesrc->mute_set && pulsesrc->mute)
    flags |= PA_STREAM_START_MUTED;

  if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted,
          flags) < 0) {
    goto connect_failed;
  }

  /* our clock will now start from 0 again */
  clock = GST_AUDIO_CLOCK (GST_AUDIO_BASE_SRC (pulsesrc)->clock);
  gst_audio_clock_reset (clock, 0);

  pulsesrc->corked = TRUE;

  for (;;) {
    pa_stream_state_t state;

    state = pa_stream_get_state (pulsesrc->stream);

    if (!PA_STREAM_IS_GOOD (state))
      goto stream_is_bad;

    if (state == PA_STREAM_READY)
      break;

    /* Wait until the stream is ready */
    pa_threaded_mainloop_wait (pulsesrc->mainloop);
  }
  pulsesrc->stream_connected = TRUE;

  /* store the source output index so it can be accessed via a property */
  pulsesrc->source_output_idx = pa_stream_get_index (pulsesrc->stream);
  g_object_notify (G_OBJECT (pulsesrc), "source-output-index");

  if (pulsesrc->volume_set) {
    gst_pulsesrc_set_stream_volume (pulsesrc, pulsesrc->volume);
    pulsesrc->volume_set = FALSE;
  }

  /* get the actual buffering properties now */
  actual = pa_stream_get_buffer_attr (pulsesrc->stream);

  GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength);
  GST_INFO_OBJECT (pulsesrc, "tlength:   %d (wanted: %d)",
      actual->tlength, wanted.tlength);
  GST_INFO_OBJECT (pulsesrc, "prebuf:    %d", actual->prebuf);
  GST_INFO_OBJECT (pulsesrc, "minreq:    %d (wanted %d)", actual->minreq,
      wanted.minreq);
  GST_INFO_OBJECT (pulsesrc, "fragsize:  %d (wanted %d)",
      actual->fragsize, wanted.fragsize);

  if (actual->fragsize >= wanted.fragsize) {
    spec->segsize = actual->fragsize;
  } else {
    spec->segsize = actual->fragsize * (wanted.fragsize / actual->fragsize);
  }
  spec->segtotal = actual->maxlength / spec->segsize;

  if (!pulsesrc->paused) {
    GST_DEBUG_OBJECT (pulsesrc, "uncorking because we are playing");
    gst_pulsesrc_set_corked (pulsesrc, FALSE, FALSE);
  }
  pa_threaded_mainloop_unlock (pulsesrc->mainloop);

  return TRUE;

  /* ERRORS */
connect_failed:
  {
    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
        ("Failed to connect stream: %s",
            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
    goto unlock_and_fail;
  }
stream_is_bad:
  {
    GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
        ("Failed to connect stream: %s",
            pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
    goto unlock_and_fail;
  }
unlock_and_fail:
  {
    gst_pulsesrc_destroy_stream (pulsesrc);

    pa_threaded_mainloop_unlock (pulsesrc->mainloop);
    return FALSE;
  }
}
Пример #27
0
static int control(struct ao *ao, enum aocontrol cmd, void *arg)
{
    struct priv *priv = ao->priv;
    switch (cmd) {
    case AOCONTROL_GET_MUTE:
    case AOCONTROL_GET_VOLUME: {
        uint32_t devidx = pa_stream_get_index(priv->stream);
        pa_threaded_mainloop_lock(priv->mainloop);
        if (!waitop(priv, pa_context_get_sink_input_info(priv->context, devidx,
                                                         info_func, ao))) {
            GENERIC_ERR_MSG(priv->context,
                            "pa_stream_get_sink_input_info() failed");
            return CONTROL_ERROR;
        }
        // Warning: some information in pi might be unaccessible, because
        // we naively copied the struct, without updating pointers etc.
        // Pointers might point to invalid data, accessors might fail.
        if (cmd == AOCONTROL_GET_VOLUME) {
            ao_control_vol_t *vol = arg;
            if (priv->pi.volume.channels != 2)
                vol->left = vol->right =
                    pa_cvolume_avg(&priv->pi.volume) * 100 / PA_VOLUME_NORM;
            else {
                vol->left = priv->pi.volume.values[0] * 100 / PA_VOLUME_NORM;
                vol->right = priv->pi.volume.values[1] * 100 / PA_VOLUME_NORM;
            }
        } else if (cmd == AOCONTROL_GET_MUTE) {
            bool *mute = arg;
            *mute = priv->pi.mute;
        }
        return CONTROL_OK;
    }

    case AOCONTROL_SET_MUTE:
    case AOCONTROL_SET_VOLUME: {
        pa_operation *o;

        pa_threaded_mainloop_lock(priv->mainloop);
        uint32_t stream_index = pa_stream_get_index(priv->stream);
        if (cmd == AOCONTROL_SET_VOLUME) {
            const ao_control_vol_t *vol = arg;
            struct pa_cvolume volume;

            pa_cvolume_reset(&volume, ao->channels);
            if (volume.channels != 2)
                pa_cvolume_set(&volume, volume.channels,
                               vol->left * PA_VOLUME_NORM / 100);
            else {
                volume.values[0] = vol->left * PA_VOLUME_NORM / 100;
                volume.values[1] = vol->right * PA_VOLUME_NORM / 100;
            }
            o = pa_context_set_sink_input_volume(priv->context, stream_index,
                                                 &volume, NULL, NULL);
            if (!o) {
                pa_threaded_mainloop_unlock(priv->mainloop);
                GENERIC_ERR_MSG(priv->context,
                                "pa_context_set_sink_input_volume() failed");
                return CONTROL_ERROR;
            }
        } else if (cmd == AOCONTROL_SET_MUTE) {
            const bool *mute = arg;
            o = pa_context_set_sink_input_mute(priv->context, stream_index,
                                               *mute, NULL, NULL);
            if (!o) {
                pa_threaded_mainloop_unlock(priv->mainloop);
                GENERIC_ERR_MSG(priv->context,
                                "pa_context_set_sink_input_mute() failed");
                return CONTROL_ERROR;
            }
        } else
            abort();
        /* We don't wait for completion here */
        pa_operation_unref(o);
        pa_threaded_mainloop_unlock(priv->mainloop);
        return CONTROL_OK;
    }
    default:
        return CONTROL_UNKNOWN;
    }
}
JNIEXPORT jint JNICALL
Java_org_jitsi_impl_neomedia_pulseaudio_PA_stream_1get_1index
    (JNIEnv *env, jclass clazz, jlong s)
{
    return pa_stream_get_index((pa_stream *) (intptr_t) s);
}
Пример #29
0
static int pulse_open(int fmt, int rate, int nch) {
    pa_sample_spec ss;
    pa_operation *o = NULL;
    int success;

    assert(!mainloop);
    assert(!context);
    assert(!stream);
    assert(!connected);

    switch(fmt)
    {
        case FMT_U8:
            ss.format = PA_SAMPLE_U8;
            break;
        case FMT_S16_LE:
            ss.format = PA_SAMPLE_S16LE;
            break;
        case FMT_S16_BE:
            ss.format = PA_SAMPLE_S16BE;
            break;

#ifdef PA_SAMPLE_S24_32LE
        case FMT_S24_LE:
            ss.format = PA_SAMPLE_S24_32LE;
            break;
        case FMT_S24_BE:
            ss.format = PA_SAMPLE_S24_32BE;
            break;
#endif

#ifdef PA_SAMPLE_S32LE
        case FMT_S32_LE:
            ss.format = PA_SAMPLE_S32LE;
            break;
        case FMT_S32_BE:
            ss.format = PA_SAMPLE_S32BE;
            break;
#endif

	case FMT_FLOAT:
            ss.format = PA_SAMPLE_FLOAT32NE;
            break;
        default:
            return FALSE;
    }
    ss.rate = rate;
    ss.channels = nch;

    if (!pa_sample_spec_valid(&ss))
        return FALSE;

    if (!(mainloop = pa_threaded_mainloop_new())) {
        ERROR ("Failed to allocate main loop");
        goto fail;
    }

    pa_threaded_mainloop_lock(mainloop);

    if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Audacious"))) {
        ERROR ("Failed to allocate context");
        goto unlock_and_fail;
    }

    pa_context_set_state_callback(context, context_state_cb, NULL);
    pa_context_set_subscribe_callback(context, subscribe_cb, NULL);

    if (pa_context_connect(context, NULL, 0, NULL) < 0) {
        ERROR ("Failed to connect to server: %s", pa_strerror(pa_context_errno(context)));
        goto unlock_and_fail;
    }

    if (pa_threaded_mainloop_start(mainloop) < 0) {
        ERROR ("Failed to start main loop");
        goto unlock_and_fail;
    }

    /* Wait until the context is ready */
    pa_threaded_mainloop_wait(mainloop);

    if (pa_context_get_state(context) != PA_CONTEXT_READY) {
        ERROR ("Failed to connect to server: %s", pa_strerror(pa_context_errno(context)));
        goto unlock_and_fail;
    }

    if (!(stream = pa_stream_new(context, "Audacious", &ss, NULL))) {
        ERROR ("Failed to create stream: %s", pa_strerror(pa_context_errno(context)));
        goto unlock_and_fail;
    }

    pa_stream_set_state_callback(stream, stream_state_cb, NULL);
    pa_stream_set_write_callback(stream, stream_request_cb, NULL);
    pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL);

    /* Connect stream with sink and default volume */
    /* Buffer struct */

    int aud_buffer = aud_get_int(NULL, "output_buffer_size");
    size_t buffer_size = pa_usec_to_bytes(aud_buffer, &ss) * 1000;
    pa_buffer_attr buffer = {(uint32_t) -1, buffer_size, (uint32_t) -1, (uint32_t) -1, buffer_size};

    if (pa_stream_connect_playback(stream, NULL, &buffer, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) {
        ERROR ("Failed to connect stream: %s", pa_strerror(pa_context_errno(context)));
        goto unlock_and_fail;
    }


    /* Wait until the stream is ready */
    pa_threaded_mainloop_wait(mainloop);

    if (pa_stream_get_state(stream) != PA_STREAM_READY) {
        ERROR ("Failed to connect stream: %s", pa_strerror(pa_context_errno(context)));
        goto unlock_and_fail;
    }

    /* Now subscribe to events */
    if (!(o = pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb, &success))) {
        ERROR ("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context)));
        goto unlock_and_fail;
    }

    success = 0;
    while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
        CHECK_DEAD_GOTO(fail, 1);
        pa_threaded_mainloop_wait(mainloop);
    }

    if (!success) {
        ERROR ("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context)));
        goto unlock_and_fail;
    }

    pa_operation_unref(o);

    /* Now request the initial stream info */
    if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_cb, NULL))) {
        ERROR ("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context)));
        goto unlock_and_fail;
    }

    while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
        CHECK_DEAD_GOTO(fail, 1);
        pa_threaded_mainloop_wait(mainloop);
    }

    if (!volume_valid) {
        ERROR ("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context)));
        goto unlock_and_fail;
    }
    pa_operation_unref(o);

    do_trigger = 0;
    written = 0;
    flush_time = 0;
    bytes_per_second = FMT_SIZEOF (fmt) * nch * rate;
    connected = 1;
    volume_time_event = NULL;

    pa_threaded_mainloop_unlock(mainloop);

    return TRUE;

unlock_and_fail:

    if (o)
        pa_operation_unref(o);

    pa_threaded_mainloop_unlock(mainloop);

fail:

    pulse_close();

    return FALSE;
}
Пример #30
0
FXbool PulseOutput::configure(const AudioFormat & fmt){
  const pa_sample_spec * config=nullptr;
  pa_operation *operation=nullptr;

  if (!open())
    return false;

  if (stream && fmt==af)
    return true;

  if (stream) {
    pa_stream_disconnect(stream);
    pa_stream_unref(stream);
    stream=nullptr;
    }

  pa_sample_spec spec;
  pa_channel_map cmap;

  if (!to_pulse_format(fmt,spec.format))
    goto failed;

  spec.rate     = fmt.rate;
  spec.channels = fmt.channels;


  // setup channel map
  pa_channel_map_init(&cmap);
  cmap.channels = fmt.channels;
  for (FXint i=0;i<fmt.channels;i++) {
    switch(fmt.channeltype(i)) {
      case Channel::None        : cmap.map[i] = PA_CHANNEL_POSITION_INVALID;      break;
      case Channel::Mono        : cmap.map[i] = PA_CHANNEL_POSITION_MONO;         break;
      case Channel::FrontLeft   : cmap.map[i] = PA_CHANNEL_POSITION_FRONT_LEFT;   break;
      case Channel::FrontRight  : cmap.map[i] = PA_CHANNEL_POSITION_FRONT_RIGHT;  break;
      case Channel::FrontCenter : cmap.map[i] = PA_CHANNEL_POSITION_FRONT_CENTER; break;
      case Channel::BackLeft    : cmap.map[i] = PA_CHANNEL_POSITION_REAR_LEFT;    break;
      case Channel::BackRight   : cmap.map[i] = PA_CHANNEL_POSITION_REAR_RIGHT;   break;
      case Channel::BackCenter  : cmap.map[i] = PA_CHANNEL_POSITION_REAR_CENTER;  break;
      case Channel::SideLeft    : cmap.map[i] = PA_CHANNEL_POSITION_SIDE_LEFT;    break;
      case Channel::SideRight   : cmap.map[i] = PA_CHANNEL_POSITION_SIDE_RIGHT;   break;
      case Channel::LFE         : cmap.map[i] = PA_CHANNEL_POSITION_LFE;          break;
      default: goto failed;
      }
    }

  stream = pa_stream_new(pulse_context,"Goggles Music Manager",&spec,&cmap);
  if (stream == nullptr)
    goto failed;

#ifdef DEBUG
  pa_stream_set_state_callback(stream,stream_state_callback,this);
#endif
  //pa_stream_set_write_callback(stream,stream_write_callback,this);

  if (pa_stream_connect_playback(stream,nullptr,nullptr,PA_STREAM_NOFLAGS,nullptr,nullptr)<0)
    goto failed;

  /// Wait until stream is ready
  pa_stream_state_t state;
  while((state=pa_stream_get_state(stream))!=PA_STREAM_READY) {
    if (state==PA_STREAM_FAILED || state==PA_STREAM_TERMINATED){
      goto failed;
      }
    context->wait_plugin_events();
    }

  /// Get Actual Format
  config = pa_stream_get_sample_spec(stream);
  if (!to_gap_format(config->format,af))
    goto failed;
  af.channels=config->channels;
  af.rate=config->rate;
  af.channelmap=fmt.channelmap;

  /// Get Current Volume
  operation = pa_context_get_sink_input_info(pulse_context,pa_stream_get_index(stream),sink_info_callback,this);
  if (operation) pa_operation_unref(operation);

  return true;
failed:
  GM_DEBUG_PRINT("[pulse] Unsupported pulse configuration:\n");
  fmt.debug();
  return false;
  }