예제 #1
0
파일: main.c 프로젝트: smatting/pulsemixer
void on_event(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata)
{
    if((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT) {
        /* sink input changed */
        if((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE) {
            if(idx != PA_INVALID_INDEX)
                pa_context_get_sink_input_info(c, idx, on_sink_input_update, NULL);
        }
        /* sink input removed */
        if((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
            if(idx != PA_INVALID_INDEX) {
                sink_input_remove(idx);
                view_update();
            }
        }
        /* sink input added */
        if((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) {
            if(idx != PA_INVALID_INDEX)
                pa_context_get_sink_input_info(c, idx, on_sink_input_update, NULL);
        }
    }
    if((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK) {
        /* sink changed */
        if((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE) {
            if(idx != PA_INVALID_INDEX)
                pa_context_get_sink_info_by_index(c, idx, on_sink_update, NULL);
        }
    }
}
예제 #2
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);
}
예제 #3
0
파일: backend.c 프로젝트: chrippa/xmms2
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;
}
예제 #4
0
void SinkInput::update()
{
    pa_operation *o;
    o = pa_context_get_sink_input_info(d->context->cObject(),
			d->index, SinkInput::sink_input_cb, this);
    pa_operation_unref(o);
}
void AudioSinksManager::update_sink_input_map(uint32_t sink_idx,
                                              pa_subscription_event_type_t event_type) {
    pa_operation* op = pa_context_get_sink_input_info(context, sink_idx, sink_input_info_callback,
                                                      new SinkInfoRequest(this, event_type));
    if (op) {
        pa_operation_unref(op);
    } else {
        logger->error("(AudioSinksManager) Failed to start getting sink {} info: {}", sink_idx,
                      get_pa_error());
    }
}
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;
    }
}
예제 #7
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);
}
예제 #8
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);
}
예제 #9
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);
    }
  }
예제 #10
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;
    }
}
예제 #11
0
void backend_volume_set(context_t *c, backend_entry_type type, uint32_t idx, int i, int v) {
    volume_callback_t *volume = (volume_callback_t*)malloc(sizeof(volume_callback_t));
    volume->index = i;
    volume->value = v;
    switch(type) {
        case SINK:
            pa_context_get_sink_info_by_index(c->context, idx, _cb_s_sink, volume);
            break;
        case SINK_INPUT:
            pa_context_get_sink_input_info(c->context, idx, _cb_s_sink_input, volume);
            break;
        case SOURCE:
            pa_context_get_source_info_by_index(c->context, idx, _cb_s_source, volume);
            break;
        case SOURCE_OUTPUT:
            pa_context_get_source_output_info(c->context, idx, _cb_s_source_output, volume);
            break;
        default:
            break;
    }
}
예제 #12
0
파일: pulse.c 프로젝트: rbavishi/vlc-2.2.1
static void sink_input_event(pa_context *ctx,
                             pa_subscription_event_type_t type,
                             uint32_t idx, audio_output_t *aout)
{
    pa_operation *op;

    /* Gee... PA will not provide the infos directly in the event. */
    switch (type)
    {
        case PA_SUBSCRIPTION_EVENT_REMOVE:
            msg_Err(aout, "sink input killed!");
            break;

        default:
            op = pa_context_get_sink_input_info(ctx, idx, sink_input_info_cb,
                                                aout);
            if (likely(op != NULL))
                pa_operation_unref(op);
            break;
    }
}
예제 #13
0
파일: pulseaudio.c 프로젝트: Allba/showtime
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);
}
예제 #14
0
파일: context.cpp 프로젝트: KDE/plasma-pa
void Context::subscribeCallback(pa_context *context, pa_subscription_event_type_t type, uint32_t index)
{
    Q_ASSERT(context == m_context);

    switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
    case PA_SUBSCRIPTION_EVENT_SINK:
        if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
            m_sinks.removeEntry(index);
        } else {
            if (!PAOperation(pa_context_get_sink_info_by_index(context, index, sink_cb, this))) {
                qCWarning(PLASMAPA) << "pa_context_get_sink_info_by_index() failed";
                return;
            }
        }
        break;

    case PA_SUBSCRIPTION_EVENT_SOURCE:
        if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
            m_sources.removeEntry(index);
        } else {
            if (!PAOperation(pa_context_get_source_info_by_index(context, index, source_cb, this))) {
                qCWarning(PLASMAPA) << "pa_context_get_source_info_by_index() failed";
                return;
            }
        }
        break;

    case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
        if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
            m_sinkInputs.removeEntry(index);
        } else {
            if (!PAOperation(pa_context_get_sink_input_info(context, index, sink_input_callback, this))) {
                qCWarning(PLASMAPA) << "pa_context_get_sink_input_info() failed";
                return;
            }
        }
        break;

    case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
        if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
            m_sourceOutputs.removeEntry(index);
        } else {
            if (!PAOperation(pa_context_get_source_output_info(context, index, source_output_cb, this))) {
                qCWarning(PLASMAPA) << "pa_context_get_sink_input_info() failed";
                return;
            }
        }
        break;

    case PA_SUBSCRIPTION_EVENT_CLIENT:
        if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
            m_clients.removeEntry(index);
        } else {
            if (!PAOperation(pa_context_get_client_info(context, index, client_cb, this))) {
                qCWarning(PLASMAPA) << "pa_context_get_client_info() failed";
                return;
            }
        }
        break;

    case PA_SUBSCRIPTION_EVENT_CARD:
        if ((type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
            m_cards.removeEntry(index);
        } else {
            if (!PAOperation(pa_context_get_card_info_by_index(context, index, card_cb, this))) {
                qCWarning(PLASMAPA) << "pa_context_get_card_info_by_index() failed";
                return;
            }
        }
        break;

    case PA_SUBSCRIPTION_EVENT_SERVER:
        if (!PAOperation(pa_context_get_server_info(context, server_cb, this))) {
            qCWarning(PLASMAPA) << "pa_context_get_server_info() failed";
            return;
        }
        break;

    }
}
예제 #15
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;
    }
}
예제 #16
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;
}
예제 #17
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;
  }
예제 #18
0
void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index)
{
	switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
		case PA_SUBSCRIPTION_EVENT_SINK:
			if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
                //w->removeSink(index);
				printf("INF: suppose to removeSink(index)\n");
			else {
				pa_operation *o;

				if (!(o = pa_context_get_sink_info_by_index(c, index, sink_cb, NULL))) {
                    //show_error("pa_context_get_sink_info_by_index() failed");
					printf("func.c:<error> pa_context_get_sink_info_by_index() failed\n");
					return;
				}
				pa_operation_unref(o);
			}

			break;

		case PA_SUBSCRIPTION_EVENT_SOURCE:
			if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
                //w->removeSource(index);
				printf("func.c:INF: suppose to removeSource(index)\n");

			else {
				pa_operation *o;
				if (!(o = pa_context_get_source_info_by_index(c, index, source_cb, NULL))) {
                    //show_error("pa_context_get_source_info_by_index() failed");
					printf("func.c:<error> pa_context_get_source_info_by_index() failed\n");
					return;
				}
				pa_operation_unref(o);
			}

			break;

		case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
			if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
                //w->removeSinkInput(index);
				printf("func.c:INF: suppose to removeSinkInput(index)\n");
			else {
				pa_operation *o;
				if (!(o = pa_context_get_sink_input_info(c, index, sink_input_cb, NULL))) {
                    //show_error("pa_context_get_sink_input_info() failed");
					printf("func.c:<error> pa_context_get_sink_input_info() failed");
					return;
				}
				pa_operation_unref(o);
			}
			break;

		case PA_SUBSCRIPTION_EVENT_CLIENT:
			if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
                //w->removeClient(index);
				printf("func.c:INF: suppose to removeClient(index)\n");

			else {
				pa_operation *o;
				if (!(o = pa_context_get_client_info(c, index, client_cb, NULL))) {
                    //show_error("pa_context_get_client_info() failed");
					printf("func.c:<error> pa_context_get_client_info() failed\n");
					return;
				}
				pa_operation_unref(o);
			}
			break;

		case PA_SUBSCRIPTION_EVENT_SERVER:
			printf("func.c: pa_subscription_event_server triggered\n");
			{
				pa_operation *o;
				if (!(o = pa_context_get_server_info(c, server_info_cb, NULL))) {
					//show_error("pa_context_get_server_info() failed");
					printf("func.c:<error> pa_context_get_server_info() failed\n");
					return;
				}
				pa_operation_unref(o);
			}

			break;
	}
}