Esempio n. 1
0
/**
 * Setup a new stream based on the properties of the given audio_buf
 */
static void
stream_setup(pa_audio_mode_t *pam, audio_buf_t *ab)
{
  pa_stream *s;
  char buf[100];
  int flags = 0;
#if PA_API_VERSION >= 12
  pa_proplist *pl;
  media_pipe_t *mp = ab->ab_mp;
#endif
  pa_channel_map map;
  pa_cvolume cv;

  memset(&pam->ss, 0, sizeof(pa_sample_spec));

  pam->ss.format = ab->ab_isfloat ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE;
  pam->ss.rate = ab->ab_samplerate;

  switch(ab->ab_format) {
  case AM_FORMAT_PCM_STEREO:
    pam->ss.channels = 2;
    pa_channel_map_init_stereo(&map);
    break;

  case AM_FORMAT_PCM_5DOT0:
    pam->ss.channels = 5;
    pa_channel_map_init(&map);

    map.channels = 5;
    map.map[0] = PA_CHANNEL_POSITION_LEFT;
    map.map[1] = PA_CHANNEL_POSITION_RIGHT;
    map.map[2] = PA_CHANNEL_POSITION_CENTER;
    map.map[3] = PA_CHANNEL_POSITION_SIDE_LEFT;
    map.map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT;
    break;

  case AM_FORMAT_PCM_5DOT1:
    pam->ss.channels = 6;
    pa_channel_map_init(&map);

    map.channels = 6;
    map.map[0] = PA_CHANNEL_POSITION_LEFT;
    map.map[1] = PA_CHANNEL_POSITION_RIGHT;
    map.map[2] = PA_CHANNEL_POSITION_CENTER;
    map.map[3] = PA_CHANNEL_POSITION_LFE;
    map.map[4] = PA_CHANNEL_POSITION_SIDE_LEFT;
    map.map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT;
    break;

  case AM_FORMAT_PCM_7DOT1:
    pam->ss.channels = 8;
    pa_channel_map_init(&map);
    map.channels = 8;
    map.map[0] = PA_CHANNEL_POSITION_LEFT;
    map.map[1] = PA_CHANNEL_POSITION_RIGHT;
    map.map[2] = PA_CHANNEL_POSITION_CENTER;
    map.map[3] = PA_CHANNEL_POSITION_LFE;
    map.map[4] = PA_CHANNEL_POSITION_SIDE_LEFT;
    map.map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT;
    map.map[6] = PA_CHANNEL_POSITION_REAR_LEFT;
    map.map[7] = PA_CHANNEL_POSITION_REAR_RIGHT;
    break;

  case AM_FORMAT_PCM_6DOT1:
    pam->ss.channels = 7;
    pa_channel_map_init(&map);
    map.channels = 7;
    map.map[0] = PA_CHANNEL_POSITION_LEFT;
    map.map[1] = PA_CHANNEL_POSITION_RIGHT;
    map.map[2] = PA_CHANNEL_POSITION_CENTER;
    map.map[3] = PA_CHANNEL_POSITION_LFE;
    map.map[4] = PA_CHANNEL_POSITION_SIDE_LEFT;
    map.map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT;
    map.map[6] = PA_CHANNEL_POSITION_REAR_CENTER;
    break;

  default:
    abort();
  }

  TRACE(TRACE_DEBUG, "PA", "Created stream %s",
	pa_sample_spec_snprint(buf, sizeof(buf), &pam->ss));

#if PA_API_VERSION >= 12
  pl = pa_proplist_new();
  if(mp->mp_flags & MP_VIDEO)
    pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "video");
  else
    pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "music");

  s = pa_stream_new_with_proplist(pam->context, "Showtime playback", 
				  &pam->ss, &map, pl);  
  pa_proplist_free(pl);

#else
  s = pa_stream_new(pam->context, "Showtime playback", &pam->ss, &map);  
#endif
  
  pa_stream_set_state_callback(s, stream_state_callback, pam);
  pa_stream_set_write_callback(s, stream_write_callback, pam);

  flags |= PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING;

  memset(&cv, 0, sizeof(cv));
  pa_cvolume_set(&cv, pam->ss.channels, pam->mastervol);
#if 1
  pa_buffer_attr pba = {0};

  pba.fragsize = (uint32_t)-1;
  pba.maxlength = 16 * 1024;
  pba.minreq    = 3  * 1024;
  pba.prebuf    = 8  * 1024;
  pba.tlength   = 12 * 1024;
#endif
  pa_stream_connect_playback(s, NULL, &pba, flags, &cv, NULL);

  pam->stream = s;
  pam->cur_rate   = ab->ab_samplerate;
  pam->cur_format = ab->ab_format;
  pam->cur_isfloat = ab->ab_isfloat;
}
Esempio n. 2
0
void Sounds::reload() {
  if (m_ctx) {
    destroy();
  }

  // This can not happen but just in case
  if (m_loop) {
    destroy();
  }

  m_loop = pa_threaded_mainloop_new();

  pa_proplist *prop = pa_proplist_new();
#ifdef SAILFISH
  pa_proplist_sets(prop, PA_PROP_MEDIA_ROLE, "event");
#else
  pa_proplist_sets(prop, PA_PROP_MEDIA_ROLE, MEDIA_ROLE);
#endif

  pa_proplist_sets(prop, PA_PROP_APPLICATION_NAME,
		   qPrintable(QCoreApplication::instance()->applicationName()));
#ifdef SAILFISH
  pa_proplist_sets(prop, PA_PROP_APPLICATION_PROCESS_BINARY, "ngfd");
#endif

  m_ctx = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(m_loop), NULL, prop);
  pa_proplist_free(prop);

  if (!m_ctx) {
    qmlInfo(this) << "Failed to create pulse audio context";
    return;
  }

  pa_context_set_state_callback(m_ctx, (pa_context_notify_cb_t)contextStateCallback, m_loop);

  if (pa_context_connect(m_ctx, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) {
    pa_context_unref(m_ctx);
    m_ctx = 0;

    qmlInfo(this) << "Failed to connect to pulse audio";
    return;
  }

  pa_threaded_mainloop_lock(m_loop);
  if (pa_threaded_mainloop_start(m_loop) < 0) {
    pa_threaded_mainloop_unlock(m_loop);
    pa_context_disconnect(m_ctx);
    pa_context_unref(m_ctx);
    m_ctx = 0;
    qmlInfo(this) << "Failed to start pulse audio loop";
    return;
  }

  while (true) {
    bool out = false;

    switch (pa_context_get_state(m_ctx)) {
    case PA_CONTEXT_UNCONNECTED:
    case PA_CONTEXT_CONNECTING:
    case PA_CONTEXT_AUTHORIZING:
    case PA_CONTEXT_SETTING_NAME:
      pa_threaded_mainloop_wait(m_loop);
      continue;

    case PA_CONTEXT_READY:
      out = true;
      break;

    case PA_CONTEXT_FAILED:
    case PA_CONTEXT_TERMINATED:
      pa_threaded_mainloop_unlock(m_loop);
      pa_context_disconnect(m_ctx);
      pa_context_unref(m_ctx);
      m_ctx = 0;
      qmlInfo(this) << "Failed to connect to pulse audio server";
      return;
    }

    if (out) {
      break;
    }
  }

  pa_context_set_state_callback(m_ctx, NULL, NULL);
  pa_threaded_mainloop_unlock(m_loop);

  for (QHash<QString, SoundFileInfo *>::const_iterator iter = m_files.begin();
	 iter != m_files.end(); iter++) {
    cache(iter.key());
  }
}
/* Generic sink state change logic. Used by raw_sink and voip_sink */
int voice_sink_set_state(pa_sink *s, pa_sink *other, pa_sink_state_t state) {
    struct userdata *u;
    pa_sink *om_sink;

    pa_sink_assert_ref(s);
    pa_assert_se(u = s->userdata);
    if (!other) {
        pa_log_debug("other sink not initialized or freed");
        return 0;
    }
    pa_sink_assert_ref(other);
    om_sink = u->master_sink;

    if (u->hw_sink_input && PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->hw_sink_input))) {
        if (pa_sink_input_get_state(u->hw_sink_input) == PA_SINK_INPUT_CORKED) {
            if (PA_SINK_IS_OPENED(state) ||
                PA_SINK_IS_OPENED(pa_sink_get_state(other)) ||
                pa_atomic_load(&u->cmt_connection.dl_state) == CMT_DL_ACTIVE) {
                pa_sink_input_cork(u->hw_sink_input, FALSE);
                pa_log_debug("hw_sink_input uncorked");
            }
        }
        else {
            if (state == PA_SINK_SUSPENDED &&
                pa_sink_get_state(other) == PA_SINK_SUSPENDED &&
                pa_atomic_load(&u->cmt_connection.dl_state) != CMT_DL_ACTIVE) {
                pa_sink_input_cork(u->hw_sink_input, TRUE);
                pa_log_debug("hw_sink_input corked");
            }
        }
    }

    if (om_sink == NULL) {
        pa_log_info("No master sink, assuming primary mixer tuning.\n");
        pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_PRI);
    }
    else if (pa_atomic_load(&u->cmt_connection.dl_state) == CMT_DL_ACTIVE ||
            (pa_sink_get_state(u->voip_sink) <= PA_SINK_SUSPENDED &&
             voice_voip_sink_used_by(u))) {
        if (pa_atomic_load(&u->mixer_state) == PROP_MIXER_TUNING_PRI) {
             pa_proplist *p = pa_proplist_new();
             pa_assert(p);
             pa_proplist_sets(p, PROP_MIXER_TUNING_MODE, PROP_MIXER_TUNING_ALT_S);
             pa_sink_update_proplist(om_sink, PA_UPDATE_REPLACE, p);
             pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_ALT);
             pa_proplist_free(p);
             if (u->sidetone_enable)
                 voice_enable_sidetone(u,1);
        }
    }
    else {
        if (pa_atomic_load(&u->mixer_state) == PROP_MIXER_TUNING_ALT) {
            pa_proplist *p = pa_proplist_new();
            pa_assert(p);
            pa_proplist_sets(p, PROP_MIXER_TUNING_MODE, PROP_MIXER_TUNING_PRI_S);
            pa_sink_update_proplist(om_sink, PA_UPDATE_REPLACE, p);
            pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_PRI);
            pa_proplist_free(p);
            voice_enable_sidetone(u,0);

        }
    }

    return 0;
}
Esempio n. 4
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;
}
Esempio n. 5
0
pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
    pa_module *m = NULL;
    pa_bool_t (*load_once)(void);
    const char* (*get_deprecated)(void);
    pa_modinfo *mi;

    pa_assert(c);
    pa_assert(name);

    if (c->disallow_module_loading)
        goto fail;

    m = pa_xnew(pa_module, 1);
    m->name = pa_xstrdup(name);
    m->argument = pa_xstrdup(argument);
    m->load_once = FALSE;
    m->proplist = pa_proplist_new();

    if (!(m->dl = lt_dlopenext(name))) {
        pa_log("Failed to open module \"%s\": %s", name, lt_dlerror());
        goto fail;
    }

    if ((load_once = (pa_bool_t (*)(void)) pa_load_sym(m->dl, name, PA_SYMBOL_LOAD_ONCE))) {

        m->load_once = load_once();

        if (m->load_once) {
            pa_module *i;
            uint32_t idx;
            /* OK, the module only wants to be loaded once, let's make sure it is */

            for (i = pa_idxset_first(c->modules, &idx); i; i = pa_idxset_next(c->modules, &idx)) {
                if (strcmp(name, i->name) == 0) {
                    pa_log("Module \"%s\" should be loaded once at most. Refusing to load.", name);
                    goto fail;
                }
            }
        }
    }

    if ((get_deprecated = (const char* (*) (void)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_DEPRECATE))) {
        const char *t;

        if ((t = get_deprecated()))
            pa_log_warn("%s is deprecated: %s", name, t);
    }

    if (!(m->init = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_INIT))) {
        pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name);
        goto fail;
    }

    m->done = (void (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_DONE);
    m->get_n_used = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_N_USED);
    m->userdata = NULL;
    m->core = c;
    m->unload_requested = FALSE;

    if (m->init(m) < 0) {
        pa_log_error("Failed to load  module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
        goto fail;
    }

    pa_assert_se(pa_idxset_put(c->modules, m, &m->index) >= 0);
    pa_assert(m->index != PA_IDXSET_INVALID);

    pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : "");

    pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index);

    if ((mi = pa_modinfo_get_by_handle(m->dl, name))) {

        if (mi->author && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_AUTHOR))
            pa_proplist_sets(m->proplist, PA_PROP_MODULE_AUTHOR, mi->author);

        if (mi->description && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_DESCRIPTION))
            pa_proplist_sets(m->proplist, PA_PROP_MODULE_DESCRIPTION, mi->description);

        if (mi->version && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_VERSION))
            pa_proplist_sets(m->proplist, PA_PROP_MODULE_VERSION, mi->version);

        pa_modinfo_free(mi);
    }

    return m;

fail:

    if (m) {
        if (m->proplist)
            pa_proplist_free(m->proplist);

        pa_xfree(m->argument);
        pa_xfree(m->name);

        if (m->dl)
            lt_dlclose(m->dl);

        pa_xfree(m);
    }

    return NULL;
}
Esempio n. 6
0
AudioStream::AudioStream(pa_context *c,
                         pa_threaded_mainloop *m,
                         const char *desc,
                         int type,
                         unsigned samplrate,
                         const PaDeviceInfos* infos,
                         bool ec)
    : audiostream_(0), mainloop_(m)
{
    const pa_channel_map channel_map = infos->channel_map;

    pa_sample_spec sample_spec = {
        PA_SAMPLE_S16LE, // PA_SAMPLE_FLOAT32LE,
        samplrate,
        channel_map.channels
    };

    RING_DBG("%s: trying to create stream with device %s (%dHz, %d channels)", desc, infos->name.c_str(), samplrate, channel_map.channels);

    assert(pa_sample_spec_valid(&sample_spec));
    assert(pa_channel_map_valid(&channel_map));

    std::unique_ptr<pa_proplist, decltype(pa_proplist_free)&> pl (pa_proplist_new(), pa_proplist_free);
    pa_proplist_sets(pl.get(), PA_PROP_FILTER_WANT, "echo-cancel");

    audiostream_ = pa_stream_new_with_proplist(c, desc, &sample_spec, &channel_map, ec ? pl.get() : nullptr);
    if (!audiostream_) {
        RING_ERR("%s: pa_stream_new() failed : %s" , desc, pa_strerror(pa_context_errno(c)));
        throw std::runtime_error("Could not create stream\n");
    }

    pa_buffer_attr attributes;
    attributes.maxlength = pa_usec_to_bytes(160 * PA_USEC_PER_MSEC, &sample_spec);
    attributes.tlength = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec);
    attributes.prebuf = 0;
    attributes.fragsize = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec);
    attributes.minreq = (uint32_t) -1;

    {
        PulseMainLoopLock lock(mainloop_);
        const pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE);

        if (type == PLAYBACK_STREAM || type == RINGTONE_STREAM) {
            pa_stream_connect_playback(audiostream_,
                    infos->name.empty() ? NULL : infos->name.c_str(),
                    &attributes,
                    flags,
                    NULL, NULL);
        } else if (type == CAPTURE_STREAM) {
            pa_stream_connect_record(audiostream_,
                    infos->name.empty() ? NULL : infos->name.c_str(),
                    &attributes,
                    flags);
        }
    }

    pa_stream_set_state_callback(audiostream_, [](pa_stream* s, void* user_data){
        static_cast<AudioStream*>(user_data)->stateChanged(s);
    }, this);
    pa_stream_set_moved_callback(audiostream_, [](pa_stream* s, void* user_data){
        static_cast<AudioStream*>(user_data)->moved(s);
    }, this);
}
Esempio n. 7
0
static int
pulseaudio_audio_reconfig(audio_decoder_t *ad)
{
  decoder_t *d = (decoder_t *)ad;
  int i;

  pa_threaded_mainloop_lock(mainloop);

  if(pulseaudio_make_context_ready()) {
    pa_threaded_mainloop_unlock(mainloop);
    return -1;
  }

  if(d->s) {
    pa_stream_disconnect(d->s);
    pa_stream_unref(d->s);
  }

  pa_channel_map map;


  ad->ad_out_sample_rate = ad->ad_in_sample_rate;
  d->ss.rate = ad->ad_in_sample_rate;
  
  switch(ad->ad_in_sample_format) {
  case AV_SAMPLE_FMT_S32:
  case AV_SAMPLE_FMT_S32P:
    ad->ad_out_sample_format = AV_SAMPLE_FMT_S32;
    d->ss.format = PA_SAMPLE_S32NE;
    d->framesize = sizeof(int32_t);
    break;

  case AV_SAMPLE_FMT_S16:
  case AV_SAMPLE_FMT_S16P:
    ad->ad_out_sample_format = AV_SAMPLE_FMT_S16;
    d->ss.format = PA_SAMPLE_S16NE;
    d->framesize = sizeof(int16_t);
    break;

  default:
    ad->ad_out_sample_format = AV_SAMPLE_FMT_FLT;
    d->ss.format = PA_SAMPLE_FLOAT32NE;
    d->framesize = sizeof(float);
    break;
  }

  switch(ad->ad_in_channel_layout) {
  case AV_CH_LAYOUT_MONO:
    d->ss.channels = 1;
    ad->ad_out_channel_layout = AV_CH_LAYOUT_MONO;
    pa_channel_map_init_mono(&map);
    break;


  case AV_CH_LAYOUT_STEREO:
    d->ss.channels = 2;
    ad->ad_out_channel_layout = AV_CH_LAYOUT_STEREO;
    pa_channel_map_init_stereo(&map);

    
  default:
    pa_channel_map_init(&map);
    for(i = 0; i < sizeof(av2pa_map) / sizeof(av2pa_map[0]); i++) {
      if(ad->ad_in_channel_layout & av2pa_map[i].avmask) {
	ad->ad_out_channel_layout |= av2pa_map[i].avmask;
	map.map[map.channels++] = av2pa_map[i].papos;
      }
    }
    d->ss.channels = map.channels;
    break;
  }

  d->framesize *= d->ss.channels;

  ad->ad_tile_size = pa_context_get_tile_size(ctx, &d->ss) / d->framesize;

  char buf[100];
  char buf2[PA_CHANNEL_MAP_SNPRINT_MAX];
  TRACE(TRACE_DEBUG, "PA", "Created stream %s [%s] (tilesize=%d)",
	pa_sample_spec_snprint(buf, sizeof(buf), &d->ss),
	pa_channel_map_snprint(buf2, sizeof(buf2), &map),
	ad->ad_tile_size);

#if PA_API_VERSION >= 12
  pa_proplist *pl = pa_proplist_new();
  media_pipe_t *mp = ad->ad_mp;
  if(mp->mp_flags & MP_VIDEO)
    pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "video");
  else
    pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "music");

  d->s = pa_stream_new_with_proplist(ctx, "Showtime playback", 
				     &d->ss, &map, pl);
  pa_proplist_free(pl);

#else
  d->s = pa_stream_new(ctx, "Showtime playback", &ss, &map);  
#endif
 
  int flags = 0;

  pa_stream_set_state_callback(d->s, stream_state_callback, d);
  pa_stream_set_write_callback(d->s, stream_write_callback, d);

  flags |= PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING;

  pa_stream_connect_playback(d->s, NULL, NULL, flags, NULL, NULL);

  while(1) {
    switch(pa_stream_get_state(d->s)) {
    case PA_STREAM_UNCONNECTED:
    case PA_STREAM_CREATING:
      pa_threaded_mainloop_wait(mainloop);
      continue;

    case PA_STREAM_READY:
      pa_threaded_mainloop_unlock(mainloop);
      return 0;

    case PA_STREAM_TERMINATED:
    case PA_STREAM_FAILED:
      pa_threaded_mainloop_unlock(mainloop);
      return 1;
    }
  }
}
Esempio n. 8
0
int soundio_pulseaudio_init(struct SoundIoPrivate *si) {
    struct SoundIo *soundio = &si->pub;
    struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio;

    sipa->device_scan_queued = true;

    sipa->main_loop = pa_threaded_mainloop_new();
    if (!sipa->main_loop) {
        destroy_pa(si);
        return SoundIoErrorNoMem;
    }

    pa_mainloop_api *main_loop_api = pa_threaded_mainloop_get_api(sipa->main_loop);

    sipa->props = pa_proplist_new();
    if (!sipa->props) {
        destroy_pa(si);
        return SoundIoErrorNoMem;
    }

    sipa->pulse_context = pa_context_new_with_proplist(main_loop_api, soundio->app_name, sipa->props);
    if (!sipa->pulse_context) {
        destroy_pa(si);
        return SoundIoErrorNoMem;
    }

    pa_context_set_subscribe_callback(sipa->pulse_context, subscribe_callback, si);
    pa_context_set_state_callback(sipa->pulse_context, context_state_callback, si);

    int err = pa_context_connect(sipa->pulse_context, NULL, (pa_context_flags_t)0, NULL);
    if (err) {
        destroy_pa(si);
        return SoundIoErrorInitAudioBackend;
    }

    if (pa_threaded_mainloop_start(sipa->main_loop)) {
        destroy_pa(si);
        return SoundIoErrorNoMem;
    }

    pa_threaded_mainloop_lock(sipa->main_loop);

    // block until ready
    while (!sipa->ready_flag)
        pa_threaded_mainloop_wait(sipa->main_loop);

    if (sipa->connection_err) {
        pa_threaded_mainloop_unlock(sipa->main_loop);
        destroy_pa(si);
        return sipa->connection_err;
    }

    if ((err = subscribe_to_events(si))) {
        pa_threaded_mainloop_unlock(sipa->main_loop);
        destroy_pa(si);
        return err;
    }

    pa_threaded_mainloop_unlock(sipa->main_loop);

    si->destroy = destroy_pa;
    si->flush_events = flush_events_pa;
    si->wait_events = wait_events_pa;
    si->wakeup = wakeup_pa;
    si->force_device_scan = force_device_scan_pa;

    si->outstream_open = outstream_open_pa;
    si->outstream_destroy = outstream_destroy_pa;
    si->outstream_start = outstream_start_pa;
    si->outstream_begin_write = outstream_begin_write_pa;
    si->outstream_end_write = outstream_end_write_pa;
    si->outstream_clear_buffer = outstream_clear_buffer_pa;
    si->outstream_pause = outstream_pause_pa;
    si->outstream_get_latency = outstream_get_latency_pa;

    si->instream_open = instream_open_pa;
    si->instream_destroy = instream_destroy_pa;
    si->instream_start = instream_start_pa;
    si->instream_begin_read = instream_begin_read_pa;
    si->instream_end_read = instream_end_read_pa;
    si->instream_pause = instream_pause_pa;
    si->instream_get_latency = instream_get_latency_pa;

    return 0;
}
Esempio n. 9
0
pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
    pa_context *c;
    pa_mem_type_t type;

    pa_assert(mainloop);

    if (pa_detect_fork())
        return NULL;

    pa_init_i18n();

    c = pa_xnew0(pa_context, 1);
    PA_REFCNT_INIT(c);

    c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();

    if (name)
        pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);

#ifdef HAVE_DBUS
    c->system_bus = c->session_bus = NULL;
#endif
    c->mainloop = mainloop;
    c->playback_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    c->record_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    c->client_index = PA_INVALID_INDEX;
    c->use_rtclock = pa_mainloop_is_our_api(mainloop);

    PA_LLIST_HEAD_INIT(pa_stream, c->streams);
    PA_LLIST_HEAD_INIT(pa_operation, c->operations);

    c->error = PA_OK;
    c->state = PA_CONTEXT_UNCONNECTED;

    reset_callbacks(c);

#ifndef MSG_NOSIGNAL
#ifdef SIGPIPE
    pa_check_signal_is_blocked(SIGPIPE);
#endif
#endif

    c->conf = pa_client_conf_new();
    pa_client_conf_load(c->conf, true, true);

    c->srb_template.readfd = -1;
    c->srb_template.writefd = -1;

    c->memfd_on_local = (!c->conf->disable_memfd && pa_memfd_is_locally_supported());

    type = (c->conf->disable_shm) ? PA_MEM_TYPE_PRIVATE :
           ((!c->memfd_on_local) ?
               PA_MEM_TYPE_SHARED_POSIX : PA_MEM_TYPE_SHARED_MEMFD);

    if (!(c->mempool = pa_mempool_new(type, c->conf->shm_size, true))) {

        if (!c->conf->disable_shm) {
            pa_log_warn("Failed to allocate shared memory pool. Falling back to a normal private one.");
            c->mempool = pa_mempool_new(PA_MEM_TYPE_PRIVATE, c->conf->shm_size, true);
        }

        if (!c->mempool) {
            context_free(c);
            return NULL;
        }
    }

    return c;
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
void on_set_common(pa_proplist* p, pa_tagstruct* t, pa_core* c)
{
    pa_log_info("on_set_common");

    const char* attribute = pa_proplist_gets(p, PROPLIST_KEY_ATTRIBUTE);
    if (!attribute) {
        pa_log_error("on_set_common: attribute not found!");
        return;
    }

    if (!strcmp(attribute, PROPLIST_VALUE_GET_INFO)) {
        const char* str_device = pa_proplist_gets(p, PROPLIST_KEY_DEVICE);
        if (!str_device) {
            pa_log_error("on_set_common device not specific!");
            return;
        }

        int device_id = atoi(str_device);
        pa_sink* sink = NULL;
        pa_source* source = NULL;

        sink = find_sink(c, device_id);
        if (!sink) {
            source = find_source(c, device_id);
        }

        if (!sink && !source) {
            pa_log_error("do not find any sink or source of device %d", device_id);
            return;
        }

        int n_used = 0;
        if (sink) {
            n_used = pa_module_get_n_used(sink->module);
        }
        else {
            n_used = pa_module_get_n_used(source->module);
        }

        char value[32];
        snprintf(value, sizeof(value), "%d", n_used);
        pa_proplist* replyp = pa_proplist_new();
        pa_proplist_sets(replyp, PROPLIST_KEY_VALUE, value);
        pa_tagstruct_put_proplist(t, replyp);
        pa_proplist_free(replyp);
    }
    else if (!strcmp(attribute, PROPLIST_VALUE_REMOTE_SINK)) {
#ifdef HAVE_WEB_SOCKET
        extern void start_web_socket();
        start_web_socket();
#endif
        on_set_debug(c, p, EAUDIO_STREAM_DEVICE_VIRTUALOUPUT_REMOTE, NULL);
    }
    else if (!strcmp(attribute, PROPLIST_VALUE_FILE_SINK)) {
        const char* str_path = pa_proplist_gets(p, PROPLIST_VALUE_PATH);
        char args[64] = { 0 };
        if (str_path) {
            snprintf(args, sizeof(args), "path=%s", str_path);
        }
        on_set_debug(c, p, EAUDIO_STREAM_DEVICE_VIRTUALOUPUT_FILE, str_path ? args : NULL);
    }
    else if (!strcmp(attribute, PROPLIST_VALUE_ALSA_BUFFER)) {
        const char* str_device = pa_proplist_gets(p, PROPLIST_KEY_DEVICE);
        if (!str_device) {
            pa_log_error("on_set_common alsa-buffer device not specific!");
            return;
        }

        int device = atoi(str_device);
        pa_sink* s = find_sink(c, device);
        if (!s) {
            pa_log_error("sink not found %d", device);
            return;
        }

        pa_usec_t left_to_play = pa_sink_get_left_to_play(s);
        pa_proplist* replyp = pa_proplist_new();
        pa_proplist_set(replyp, PROPLIST_KEY_COMMAND_RESULT, &left_to_play, sizeof(left_to_play));
        pa_tagstruct_put_proplist(t, replyp);
        pa_proplist_free(replyp);
    }
    else if (!strcmp(attribute, PROPLIST_VALUE_STOP_TEST)) {
        pthread_t tid_stop;
        int err = pthread_create(&tid_stop, NULL, stop_thread, NULL);
        if (err != 0) {
            pa_log_error("can't create thread: %s\n", strerror(err));
            return;
        }
    }
#ifdef HAVE_WEB_SOCKET
        else if (!strcmp(attribute, "web-start")) {
            extern void start_web_socket();
            start_web_socket();
        }
        else if (!strcmp(attribute, "web-stop")) {
            extern void stop_web_socket();
            stop_web_socket();
        }
#endif
}
Esempio n. 12
0
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);
}
int main(int argc, char **argv) {
    pa_proplist *proplist = NULL;
    pa_mainloop *m = NULL;
    pa_mainloop_api *api = NULL;
    pa_context *context = NULL;
    struct context *ctx;
    struct audio_file *file;
    int ret;

    ctx = malloc(sizeof(struct context));
    if (!ctx) {
        errorp("Couldn't allocate async callbacks context");
        goto quit;
    }

    memset(ctx, 0, sizeof(*ctx));

    file = audio_file_new("samples/sample.wav");
    if (!file)
        goto quit;

    proplist = pa_proplist_new();
    if (!proplist) {
        error("Couldn't create a PulseAudio property list");
        goto quit;
    }

    pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "malicious-client-kill-server");

    m = pa_mainloop_new();
    if (!m) {
        error("Couldn't create PulseAudio mainloop");
        goto quit;
    }

    api = pa_mainloop_get_api(m);
    context = pa_context_new_with_proplist(api, NULL, proplist);
    if (!context) {
        error("Couldn't create client context");
        goto quit;
    }

    ctx->file = file;
    ctx->mainloop_api = api;
    ctx->context = context;
    pa_context_set_state_callback(context, context_state_callback, ctx);

    ret = pa_context_connect(context, NULL, 0, NULL);
    if (ret < 0) {
        error ("Couldn't connect to PulseAudio server: %s",
               pa_strerror(pa_context_errno(context)));
        goto quit;
    }

    pa_mainloop_run(m, &ret);

    return ret;

 quit:
     exit(EXIT_FAILURE);
}
Esempio n. 14
0
void Sounds::cache(const QString& id) {
  SoundFileInfo *info = m_files[id];

  if (!info) {
    return;
  }

  if (info->path().isEmpty()) {
    return;
  }

  if (!m_ctx) {
    return;
  }

  FileReader h(info->path());
  pa_sample_spec *spec = h.sampleSpec();

  if (!spec) {
    qmlInfo(this) << "Failed to get a sample spec";
    return;
  }

  if (!pa_sample_spec_valid(spec)) {
    qmlInfo(this) << "Failed to get a valid sample spec";
    return;
  }

  // First we set the file duration
  info->setDuration(pa_bytes_to_usec(h.size(), spec));

  pa_proplist *prop = pa_proplist_new();
  pa_proplist_sets(prop, PA_PROP_MEDIA_ROLE, "event");
#ifdef SAILFISH
  pa_proplist_sets(prop, PA_PROP_MEDIA_NAME, "camera-event");
#else
  pa_proplist_sets(prop, PA_PROP_MEDIA_NAME, qPrintable(id));
#endif
  pa_proplist_sets(prop, PA_PROP_EVENT_ID, qPrintable(id));
  pa_proplist_sets(prop, PA_PROP_MEDIA_FILENAME, qPrintable(info->path()));

#ifdef SAILFISH
  pa_proplist_sets(prop, PA_PROP_APPLICATION_PROCESS_BINARY, "ngfd");
  pa_stream *stream = pa_stream_new_with_proplist(m_ctx, "camera-event",
						  spec, NULL, prop);
#else
  pa_stream *stream = pa_stream_new_with_proplist(m_ctx, qPrintable(id),
						  spec, NULL, prop);
#endif

  pa_proplist_free(prop);
  if (!stream) {
    qmlInfo(this) << "Failed to create a pulse audio stream";
    return;
  }

  pa_stream_set_state_callback(stream, (pa_stream_notify_cb_t)streamStateCallback, m_loop);
  pa_stream_set_write_callback(stream, (pa_stream_request_cb_t)streamRequestCallback, &h);

  pa_threaded_mainloop_lock(m_loop);
  if (pa_stream_connect_upload(stream, h.size()) < 0) {
    pa_stream_unref(stream);
    pa_threaded_mainloop_unlock(m_loop);
    qmlInfo(this) << "Failed to connect pulse audio stream";
    return;
  }

  while (true) {
    bool out = false;

    switch (pa_stream_get_state(stream)) {
    case PA_STREAM_FAILED:
      qmlInfo(this) << "Failed to connect our stream to pulse audio " << pa_strerror(pa_context_errno(m_ctx));
      pa_stream_disconnect(stream);
      pa_stream_unref(stream);
      pa_threaded_mainloop_unlock(m_loop);
      return;

    case PA_STREAM_TERMINATED:
      pa_threaded_mainloop_unlock(m_loop);
      out = true;
      break;

    case PA_STREAM_READY:
    case PA_STREAM_UNCONNECTED:
    case PA_STREAM_CREATING:
      pa_threaded_mainloop_wait(m_loop);
      continue;
    }

    if (out) {
      break;
    }
  }

  pa_stream_unref(stream);
}
JNIEXPORT jlong JNICALL
Java_org_jitsi_impl_neomedia_pulseaudio_PA_proplist_1new
    (JNIEnv *env, jclass clazz)
{
    return (intptr_t) pa_proplist_new();
}
int main(int argc, const char *argv[])
{
    pa_mainloop *pa_ml = NULL;
    pa_mainloop_api *pa_mlapi = NULL;
    pa_operation *pa_op = NULL;
    pa_context *pa_ctx = NULL;

    int pa_ready = 0;
    int state = 0;
    
    pa_ml = pa_mainloop_new();
    pa_mlapi = pa_mainloop_get_api(pa_ml);
    pa_ctx = pa_context_new(pa_mlapi, "deepin");

    pa_context_connect(pa_ctx, NULL, 0, NULL);
    pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);

    for (;;) {
        if (0 == pa_ready) {
            pa_mainloop_iterate(pa_ml, 1, NULL);
            continue;
        }
        if (2 == pa_ready) {
            pa_context_disconnect(pa_ctx);
            pa_context_unref(pa_ctx);
            pa_mainloop_free(pa_ml);
            return -1;
        }
        switch (state) {
            case 0:
                if (pa_context_get_server_protocol_version (pa_ctx) < 13) {
                        return -1;
                }
                printf("server version: %d\n", pa_context_get_server_protocol_version(pa_ctx));

                pa_stream *s = NULL;
                pa_proplist   *proplist;

                pa_buffer_attr attr;
                pa_sample_spec ss;

                int res;
                char dev_name[40];

                // pa_sample_spec
                ss.channels = 1;
                ss.format = PA_SAMPLE_FLOAT32;
                ss.rate = 25;

                // pa_buffer_attr
                memset(&attr, 0, sizeof(attr));
                attr.fragsize = sizeof(float);
                attr.maxlength = (uint32_t) -1;


                // pa_proplist
                proplist = pa_proplist_new ();
                pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "deepin.sound");

                // create new stream
                if (!(s = pa_stream_new_with_proplist(pa_ctx, "Peak detect", &ss, NULL, proplist))) {
                    fprintf(stderr, "pa_stream_new error\n");
                    return -2;
                }
                pa_proplist_free(proplist);

                /*pa_stream_set_monitor_stream(s, 26);*/

                pa_stream_set_read_callback(s, on_monitor_read_callback, NULL);
                pa_stream_set_suspended_callback(s, on_monitor_suspended_callback, NULL);
                res = pa_stream_connect_record(s, NULL, &attr, 
                                               (pa_stream_flags_t) (PA_STREAM_DONT_MOVE
                                                                    |PA_STREAM_PEAK_DETECT
                                                                    |PA_STREAM_ADJUST_LATENCY));
                
                if (res < 0) {
                    fprintf(stderr, "Failed to connect monitoring stream\n");
                    return -3;
                }
                state++;
                break;
            case 1:
                usleep(100);
                break;
            case 2:
                return 0;
                break;
            default:
                return -1;
        }
        pa_mainloop_iterate(pa_ml, 1, NULL);
    }

    return 0;
}
bool AudioOutputPulseAudio::ContextConnect(void)
{
    QString fn_log_tag = "ContextConnect, ";
    if (pcontext)
    {
        VBERROR(fn_log_tag + "context appears to exist, but shouldn't (yet)");
        pa_context_unref(pcontext);
        pcontext = NULL;
        return false;
    }
    pa_proplist *proplist = pa_proplist_new();
    if (!proplist)
    {
        VBERROR(fn_log_tag + QString("failed to create new proplist"));
        return false;
    }
    pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "MythTV");
    pa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "mythtv");
    pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "video");
    pcontext =
        pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mainloop),
                                     "MythTV", proplist);
    if (!pcontext)
    {
        VBERROR(fn_log_tag + "failed to acquire new context");
        return false;
    }
    pa_context_set_state_callback(pcontext, ContextStateCallback, this);

    char *pulse_host = ChooseHost();
    int chk = pa_context_connect(
        pcontext, pulse_host, (pa_context_flags_t)0, NULL);

    delete[] pulse_host;

    if (chk < 0)
    {
        VBERROR(fn_log_tag + QString("context connect failed: %1")
                             .arg(pa_strerror(pa_context_errno(pcontext))));
        return false;
    }
    bool connected = false;
    pa_context_state_t state = pa_context_get_state(pcontext);
    for (; !connected; state = pa_context_get_state(pcontext))
    {
        switch(state)
        {
            case PA_CONTEXT_READY:
                VBAUDIO(fn_log_tag +"context connection ready");
                connected = true;
                continue;

            case PA_CONTEXT_FAILED:
            case PA_CONTEXT_TERMINATED:
                VBERROR(fn_log_tag +
                        QString("context connection failed or terminated: %1")
                        .arg(pa_strerror(pa_context_errno(pcontext))));
                return false;

            default:
                VBAUDIO(fn_log_tag + "waiting for context connection ready");
                pa_threaded_mainloop_wait(mainloop);
                break;
        }
    }

    pa_operation *op =
        pa_context_get_server_info(pcontext, ServerInfoCallback, this);

    if (op)
        pa_operation_unref(op);
    else
        VBERROR(fn_log_tag + "failed to get PulseAudio server info");

    return true;
}
Esempio n. 18
0
pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
    pa_context *c;

    pa_assert(mainloop);

    if (pa_detect_fork())
        return NULL;

    pa_init_i18n();

    c = pa_xnew0(pa_context, 1);
    PA_REFCNT_INIT(c);

    c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();

    if (name)
        pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);

#ifdef HAVE_DBUS
    c->system_bus = c->session_bus = NULL;
#endif
    c->mainloop = mainloop;
    c->playback_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    c->record_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
    c->client_index = PA_INVALID_INDEX;
    c->use_rtclock = pa_mainloop_is_our_api(mainloop);

    PA_LLIST_HEAD_INIT(pa_stream, c->streams);
    PA_LLIST_HEAD_INIT(pa_operation, c->operations);

    c->error = PA_OK;
    c->state = PA_CONTEXT_UNCONNECTED;

    reset_callbacks(c);

#ifndef MSG_NOSIGNAL
#ifdef SIGPIPE
    pa_check_signal_is_blocked(SIGPIPE);
#endif
#endif

    c->conf = pa_client_conf_new();
    pa_client_conf_load(c->conf, NULL);
#ifdef HAVE_X11
    pa_client_conf_from_x11(c->conf, NULL);
#endif
    pa_client_conf_env(c->conf);

    if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) {

        if (!c->conf->disable_shm)
            c->mempool = pa_mempool_new(FALSE, c->conf->shm_size);

        if (!c->mempool) {
            context_free(c);
            return NULL;
        }
    }

    return c;
}
bool AudioOutputPulseAudio::ConnectPlaybackStream(void)
{
    QString fn_log_tag = "ConnectPlaybackStream, ";
    pa_proplist *proplist = pa_proplist_new();
    if (!proplist)
    {
        VBERROR(fn_log_tag + QString("failed to create new proplist"));
        return false;
    }
    pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "video");
    pstream =
        pa_stream_new_with_proplist(pcontext, "MythTV playback", &sample_spec,
                                    &channel_map, proplist);
    if (!pstream)
    {
        VBERROR("failed to create new playback stream");
        return false;
    }
    pa_stream_set_state_callback(pstream, StreamStateCallback, this);
    pa_stream_set_write_callback(pstream, WriteCallback, this);
    pa_stream_set_overflow_callback(pstream, BufferFlowCallback, (char*)"over");
    pa_stream_set_underflow_callback(pstream, BufferFlowCallback,
                                     (char*)"under");
    if (set_initial_vol)
    {
        int volume = gCoreContext->GetNumSetting("MasterMixerVolume", 80);
        pa_cvolume_set(&volume_control, channels,
                       (float)volume * (float)PA_VOLUME_NORM / 100.0f);
    }
    else
        pa_cvolume_reset(&volume_control, channels);

    fragment_size = (samplerate * 25 * output_bytes_per_frame) / 1000;

    buffer_settings.maxlength = (uint32_t)-1;
    buffer_settings.tlength = fragment_size * 4;
    buffer_settings.prebuf = (uint32_t)-1;
    buffer_settings.minreq = (uint32_t)-1;

    int flags = PA_STREAM_INTERPOLATE_TIMING
        | PA_STREAM_ADJUST_LATENCY
        | PA_STREAM_AUTO_TIMING_UPDATE
        | PA_STREAM_NO_REMIX_CHANNELS;

    pa_stream_connect_playback(pstream, NULL, &buffer_settings,
                               (pa_stream_flags_t)flags, NULL, NULL);

    pa_context_state_t cstate;
    pa_stream_state_t sstate;
    bool connected = false, failed = false;

    while (!(connected || failed))
    {
        switch (cstate = pa_context_get_state(pcontext))
        {
            case PA_CONTEXT_FAILED:
            case PA_CONTEXT_TERMINATED:
                VBERROR(QString("context is stuffed, %1")
                            .arg(pa_strerror(pa_context_errno(pcontext))));
                failed = true;
                break;
            default:
                switch (sstate = pa_stream_get_state(pstream))
                {
                    case PA_STREAM_READY:
                        connected = true;
                        break;
                    case PA_STREAM_FAILED:
                    case PA_STREAM_TERMINATED:
                        VBERROR(QString("stream failed or was terminated, "
                                        "context state %1, stream state %2")
                                    .arg(cstate).arg(sstate));
                        failed = true;
                        break;
                    default:
                        pa_threaded_mainloop_wait(mainloop);
                        break;
                }
        }
    }

    const pa_buffer_attr *buf_attr = pa_stream_get_buffer_attr(pstream);
    fragment_size = buf_attr->tlength >> 2;
    soundcard_buffer_size = buf_attr->maxlength;

    VBAUDIO(QString("fragment size %1, soundcard buffer size %2")
                .arg(fragment_size).arg(soundcard_buffer_size));

    return (connected && !failed);
}
Esempio n. 20
0
int main(int argc, char *argv[]) {
    pa_mainloop* m = NULL;
    int ret = 1, c;
    char *bn, *server = NULL;
    pa_time_event *time_event = NULL;
    const char *filename = NULL;
    /* type for pa_read/_write. passed as userdata to the callbacks */
    unsigned long type = 0;

    static const struct option long_options[] = {
        {"record",       0, NULL, 'r'},
        {"playback",     0, NULL, 'p'},
        {"device",       1, NULL, 'd'},
        {"server",       1, NULL, 's'},
        {"client-name",  1, NULL, 'n'},
        {"stream-name",  1, NULL, ARG_STREAM_NAME},
        {"version",      0, NULL, ARG_VERSION},
        {"help",         0, NULL, 'h'},
        {"verbose",      0, NULL, 'v'},
        {"volume",       1, NULL, ARG_VOLUME},
        {"rate",         1, NULL, ARG_SAMPLERATE},
        {"format",       1, NULL, ARG_SAMPLEFORMAT},
        {"channels",     1, NULL, ARG_CHANNELS},
        {"channel-map",  1, NULL, ARG_CHANNELMAP},
        {"fix-format",   0, NULL, ARG_FIX_FORMAT},
        {"fix-rate",     0, NULL, ARG_FIX_RATE},
        {"fix-channels", 0, NULL, ARG_FIX_CHANNELS},
        {"no-remap",     0, NULL, ARG_NO_REMAP},
        {"no-remix",     0, NULL, ARG_NO_REMIX},
        {"latency",      1, NULL, ARG_LATENCY},
        {"process-time", 1, NULL, ARG_PROCESS_TIME},
        {"property",     1, NULL, ARG_PROPERTY},
        {"raw",          0, NULL, ARG_RAW},
        {"passthrough",  0, NULL, ARG_PASSTHROUGH},
        {"file-format",  2, NULL, ARG_FILE_FORMAT},
        {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS},
        {"latency-msec", 1, NULL, ARG_LATENCY_MSEC},
        {"process-time-msec", 1, NULL, ARG_PROCESS_TIME_MSEC},
        {"monitor-stream", 1, NULL, ARG_MONITOR_STREAM},
        {NULL,           0, NULL, 0}
    };

    setlocale(LC_ALL, "");
#ifdef ENABLE_NLS
    bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
#endif

    bn = pa_path_get_filename(argv[0]);

    if (strstr(bn, "play")) {
        mode = PLAYBACK;
        raw = false;
    } else if (strstr(bn, "record")) {
        mode = RECORD;
        raw = false;
    } else if (strstr(bn, "cat")) {
        mode = PLAYBACK;
        raw = true;
    } else if (strstr(bn, "rec") || strstr(bn, "mon")) {
        mode = RECORD;
        raw = true;
    }

    proplist = pa_proplist_new();

    while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) {

        switch (c) {
            case 'h' :
                help(bn);
                ret = 0;
                goto quit;

            case ARG_VERSION:
                printf(_("pacat %s\n"
                         "Compiled with libpulse %s\n"
                         "Linked with libpulse %s\n"),
                       PACKAGE_VERSION,
                       pa_get_headers_version(),
                       pa_get_library_version());
                ret = 0;
                goto quit;

            case 'r':
                mode = RECORD;
                break;

            case 'p':
                mode = PLAYBACK;
                break;

            case 'd':
                pa_xfree(device);
                device = pa_xstrdup(optarg);
                break;

            case 's':
                pa_xfree(server);
                server = pa_xstrdup(optarg);
                break;

            case 'n': {
                char *t;

                if (!(t = pa_locale_to_utf8(optarg)) ||
                    pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) {

                    pa_log(_("Invalid client name '%s'"), t ? t : optarg);
                    pa_xfree(t);
                    goto quit;
                }

                pa_xfree(t);
                break;
            }

            case ARG_STREAM_NAME: {
                char *t;

                if (!(t = pa_locale_to_utf8(optarg)) ||
                    pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) {

                    pa_log(_("Invalid stream name '%s'"), t ? t : optarg);
                    pa_xfree(t);
                    goto quit;
                }

                pa_xfree(t);
                break;
            }

            case 'v':
                verbose = 1;
                break;

            case ARG_VOLUME: {
                int v = atoi(optarg);
                volume = v < 0 ? 0U : (pa_volume_t) v;
                volume_is_set = true;
                break;
            }

            case ARG_CHANNELS:
                sample_spec.channels = (uint8_t) atoi(optarg);
                sample_spec_set = true;
                break;

            case ARG_SAMPLEFORMAT:
                sample_spec.format = pa_parse_sample_format(optarg);
                sample_spec_set = true;
                break;

            case ARG_SAMPLERATE:
                sample_spec.rate = (uint32_t) atoi(optarg);
                sample_spec_set = true;
                break;

            case ARG_CHANNELMAP:
                if (!pa_channel_map_parse(&channel_map, optarg)) {
                    pa_log(_("Invalid channel map '%s'"), optarg);
                    goto quit;
                }

                channel_map_set = true;
                break;

            case ARG_FIX_CHANNELS:
                flags |= PA_STREAM_FIX_CHANNELS;
                break;

            case ARG_FIX_RATE:
                flags |= PA_STREAM_FIX_RATE;
                break;

            case ARG_FIX_FORMAT:
                flags |= PA_STREAM_FIX_FORMAT;
                break;

            case ARG_NO_REMIX:
                flags |= PA_STREAM_NO_REMIX_CHANNELS;
                break;

            case ARG_NO_REMAP:
                flags |= PA_STREAM_NO_REMAP_CHANNELS;
                break;

            case ARG_LATENCY:
                if (((latency = (size_t) atoi(optarg))) <= 0) {
                    pa_log(_("Invalid latency specification '%s'"), optarg);
                    goto quit;
                }
                break;

            case ARG_PROCESS_TIME:
                if (((process_time = (size_t) atoi(optarg))) <= 0) {
                    pa_log(_("Invalid process time specification '%s'"), optarg);
                    goto quit;
                }
                break;

            case ARG_LATENCY_MSEC:
                if (((latency_msec = (int32_t) atoi(optarg))) <= 0) {
                    pa_log(_("Invalid latency specification '%s'"), optarg);
                    goto quit;
                }
                break;

            case ARG_PROCESS_TIME_MSEC:
                if (((process_time_msec = (int32_t) atoi(optarg))) <= 0) {
                    pa_log(_("Invalid process time specification '%s'"), optarg);
                    goto quit;
                }
                break;

            case ARG_PROPERTY: {
                char *t;

                if (!(t = pa_locale_to_utf8(optarg)) ||
                    pa_proplist_setp(proplist, t) < 0) {

                    pa_xfree(t);
                    pa_log(_("Invalid property '%s'"), optarg);
                    goto quit;
                }

                pa_xfree(t);
                break;
            }

            case ARG_RAW:
                raw = true;
                break;

            case ARG_PASSTHROUGH:
                flags |= PA_STREAM_PASSTHROUGH;
                break;

            case ARG_FILE_FORMAT:
                if (optarg) {
                    if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) {
                        pa_log(_("Unknown file format %s."), optarg);
                        goto quit;
                    }
                }

                raw = false;
                break;

            case ARG_LIST_FILE_FORMATS:
                pa_sndfile_dump_formats();
                ret = 0;
                goto quit;

            case ARG_MONITOR_STREAM:
                if (pa_atou(optarg, &monitor_stream) < 0) {
                    pa_log(_("Failed to parse the argument for --monitor-stream"));
                    goto quit;
                }
                break;

            default:
                goto quit;
        }
    }

    if (!pa_sample_spec_valid(&sample_spec)) {
        pa_log(_("Invalid sample specification"));
        goto quit;
    }

    if (optind+1 == argc) {
        int fd;

        filename = argv[optind];

        if ((fd = pa_open_cloexec(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
            pa_log(_("open(): %s"), strerror(errno));
            goto quit;
        }

        if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) {
            pa_log(_("dup2(): %s"), strerror(errno));
            goto quit;
        }

        pa_close(fd);

    } else if (optind+1 <= argc) {
        pa_log(_("Too many arguments."));
        goto quit;
    }

    if (!raw) {
        SF_INFO sfi;
        pa_zero(sfi);

        if (mode == RECORD) {
            /* This might patch up the sample spec */
            if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) {
                pa_log(_("Failed to generate sample specification for file."));
                goto quit;
            }

            if (file_format <= 0) {
                char *extension;
                if (filename && (extension = strrchr(filename, '.')))
                    file_format = pa_sndfile_format_from_string(extension+1);
                if (file_format <= 0)
                    file_format = SF_FORMAT_WAV;
                /* Transparently upgrade classic .wav to wavex for multichannel audio */
                if (file_format == SF_FORMAT_WAV &&
                    (sample_spec.channels > 2 ||
                    (channel_map_set &&
                    !(sample_spec.channels == 1 && channel_map.map[0] == PA_CHANNEL_POSITION_MONO) &&
                    !(sample_spec.channels == 2 && channel_map.map[0] == PA_CHANNEL_POSITION_LEFT
                                                && channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))))
                    file_format = SF_FORMAT_WAVEX;
            }

            sfi.format |= file_format;
        }

        if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO,
                                   mode == RECORD ? SFM_WRITE : SFM_READ,
                                   &sfi, 0))) {
            pa_log(_("Failed to open audio file."));
            goto quit;
        }

        if (mode == PLAYBACK) {
            if (sample_spec_set)
                pa_log(_("Warning: specified sample specification will be overwritten with specification from file."));

            if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) {
                pa_log(_("Failed to determine sample specification from file."));
                goto quit;
            }
            sample_spec_set = true;

            if (!channel_map_set) {
                /* Allow the user to overwrite the channel map on the command line */
                if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) {
                    if (sample_spec.channels > 2)
                        pa_log(_("Warning: Failed to determine channel map from file."));
                } else
                    channel_map_set = true;
            }
        }
    }

    if (!channel_map_set)
        pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);

    if (!pa_channel_map_compatible(&channel_map, &sample_spec)) {
        pa_log(_("Channel map doesn't match sample specification"));
        goto quit;
    }

    if (!raw) {
        pa_proplist *sfp;

        if (mode == PLAYBACK)
            readf_function = pa_sndfile_readf_function(&sample_spec);
        else {
            if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0)
                pa_log(_("Warning: failed to write channel map to file."));

            writef_function = pa_sndfile_writef_function(&sample_spec);
        }

        /* Fill in libsndfile prop list data */
        sfp = pa_proplist_new();
        pa_sndfile_init_proplist(sndfile, sfp);
        pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp);
        pa_proplist_free(sfp);
    }

    if (verbose) {
        char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX];

        pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."),
                mode == RECORD ? _("recording") : _("playback"),
                pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec),
                pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map));
    }

    /* Fill in client name if none was set */
    if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) {
        char *t;

        if ((t = pa_locale_to_utf8(bn))) {
            pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t);
            pa_xfree(t);
        }
    }

    /* Fill in media name if none was set */
    if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
        const char *t;

        if ((t = filename) ||
            (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME)))
            pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t);

        if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) {
            pa_log(_("Failed to set media name."));
            goto quit;
        }
    }

    /* Set up a new main loop */
    if (!(m = pa_mainloop_new())) {
        pa_log(_("pa_mainloop_new() failed."));
        goto quit;
    }

    mainloop_api = pa_mainloop_get_api(m);

    pa_assert_se(pa_signal_init(mainloop_api) == 0);
    pa_signal_new(SIGINT, exit_signal_callback, NULL);
    pa_signal_new(SIGTERM, exit_signal_callback, NULL);
#ifdef SIGUSR1
    pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL);
#endif
    pa_disable_sigpipe();

    if (raw) {
#ifdef OS_IS_WIN32
        /* need to turn on binary mode for stdio io. Windows, meh */
        setmode(mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, O_BINARY);
#endif
        if (!(stdio_event = mainloop_api->io_new(mainloop_api,
                                                 mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO,
                                                 mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT,
                                                 mode == PLAYBACK ? stdin_callback : stdout_callback, &type))) {
            pa_log(_("io_new() failed."));
            goto quit;
        }
    }

    /* Create a new connection context */
    if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) {
        pa_log(_("pa_context_new() failed."));
        goto quit;
    }

    pa_context_set_state_callback(context, context_state_callback, NULL);

    /* Connect the context */
    if (pa_context_connect(context, server, 0, NULL) < 0) {
        pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context)));
        goto quit;
    }

    if (verbose) {
        if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) {
            pa_log(_("pa_context_rttime_new() failed."));
            goto quit;
        }
    }

    /* Run the main loop */
    if (pa_mainloop_run(m, &ret) < 0) {
        pa_log(_("pa_mainloop_run() failed."));
        goto quit;
    }

quit:
    if (stream)
        pa_stream_unref(stream);

    if (context)
        pa_context_unref(context);

    if (stdio_event) {
        pa_assert(mainloop_api);
        mainloop_api->io_free(stdio_event);
    }

    if (time_event) {
        pa_assert(mainloop_api);
        mainloop_api->time_free(time_event);
    }

    if (m) {
        pa_signal_done();
        pa_mainloop_free(m);
    }

    pa_xfree(silence_buffer);
    pa_xfree(buffer);

    pa_xfree(server);
    pa_xfree(device);

    if (sndfile)
        sf_close(sndfile);

    if (proplist)
        pa_proplist_free(proplist);

    return ret;
}
Esempio n. 21
0
int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume, pa_proplist *p, uint32_t *sink_input_idx) {
    pa_scache_entry *e;
    pa_cvolume r;
    pa_proplist *merged;
    pa_bool_t pass_volume;

    pa_assert(c);
    pa_assert(name);
    pa_assert(sink);

    if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE)))
        return -1;

    merged = pa_proplist_new();
    pa_proplist_sets(merged, PA_PROP_MEDIA_NAME, name);
    pa_proplist_sets(merged, PA_PROP_EVENT_ID, name);

    if (e->lazy && !e->memchunk.memblock) {
        pa_channel_map old_channel_map = e->channel_map;

        if (pa_sound_file_load(c->mempool, e->filename, &e->sample_spec, &e->channel_map, &e->memchunk, merged) < 0)
            goto fail;

        pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index);

        if (e->volume_is_set) {
            if (pa_cvolume_valid(&e->volume))
                pa_cvolume_remap(&e->volume, &old_channel_map, &e->channel_map);
            else
                pa_cvolume_reset(&e->volume, e->sample_spec.channels);
        }
    }

    if (!e->memchunk.memblock)
        goto fail;

    pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name);

    pass_volume = TRUE;

    if (e->volume_is_set && volume != PA_VOLUME_INVALID) {
        pa_cvolume_set(&r, e->sample_spec.channels, volume);
        pa_sw_cvolume_multiply(&r, &r, &e->volume);
    } else if (e->volume_is_set)
        r = e->volume;
    else if (volume != PA_VOLUME_INVALID)
        pa_cvolume_set(&r, e->sample_spec.channels, volume);
    else
        pass_volume = FALSE;

    pa_proplist_update(merged, PA_UPDATE_REPLACE, e->proplist);

    if (p)
        pa_proplist_update(merged, PA_UPDATE_REPLACE, p);

    if (pa_play_memchunk(sink,
                         &e->sample_spec, &e->channel_map,
                         &e->memchunk,
                         pass_volume ? &r : NULL,
                         merged,
                         PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND, sink_input_idx) < 0)
        goto fail;

    pa_proplist_free(merged);

    if (e->lazy)
        time(&e->last_used_time);

    return 0;

fail:
    pa_proplist_free(merged);
    return -1;
}
Esempio n. 22
0
/**
 * Initializes the PulseAudio main loop and connects to the PulseAudio server.
 * @return a PulseAudio context on success, or NULL on error
 */
pa_context *vlc_pa_connect (vlc_object_t *obj, pa_threaded_mainloop **mlp)
{
    msg_Dbg (obj, "using library version %s", pa_get_library_version ());
    msg_Dbg (obj, " (compiled with version %s, protocol %u)",
             pa_get_headers_version (), PA_PROTOCOL_VERSION);

    /* Initialize main loop */
    pa_threaded_mainloop *mainloop = pa_threaded_mainloop_new ();
    if (unlikely(mainloop == NULL))
        return NULL;

    if (pa_threaded_mainloop_start (mainloop) < 0)
    {
        pa_threaded_mainloop_free (mainloop);
        return NULL;
    }

    /* Fill in context (client) properties */
    char *ua = var_InheritString (obj, "user-agent");
    pa_proplist *props = pa_proplist_new ();
    if (likely(props != NULL))
    {
        pa_proplist_sets (props, PA_PROP_APPLICATION_NAME, ua);
        pa_proplist_sets (props, PA_PROP_APPLICATION_ID, "org.VideoLAN.VLC");
        pa_proplist_sets (props, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION);
        pa_proplist_sets (props, PA_PROP_APPLICATION_ICON_NAME, PACKAGE_NAME);
        //pa_proplist_sets (props, PA_PROP_APPLICATION_LANGUAGE, _("C"));
        pa_proplist_sets (props, PA_PROP_APPLICATION_LANGUAGE,
                          setlocale (LC_MESSAGES, NULL));

        pa_proplist_setf (props, PA_PROP_APPLICATION_PROCESS_ID, "%lu",
                          (unsigned long) getpid ());
        //pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_BINARY,
        //                  PACKAGE_NAME);

        for (size_t max = sysconf (_SC_GETPW_R_SIZE_MAX), len = max % 1024 + 1024;
             len < max; len += 1024)
        {
            struct passwd pwbuf, *pw;
            char buf[len];

            if (getpwuid_r (getuid (), &pwbuf, buf, sizeof (buf), &pw) == 0)
            {
                if (pw != NULL)
                    pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_USER,
                                      pw->pw_name);
                break;
            }
        }

        for (size_t max = sysconf (_SC_HOST_NAME_MAX), len = max % 1024 + 1024;
             len < max; len += 1024)
        {
            char hostname[len];

            if (gethostname (hostname, sizeof (hostname)) == 0)
            {
                pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_HOST,
                                  hostname);
                break;
            }
        }

        const char *session = getenv ("XDG_SESSION_COOKIE");
        if (session != NULL)
        {
            pa_proplist_setf (props, PA_PROP_APPLICATION_PROCESS_MACHINE_ID,
                              "%.32s", session); /* XXX: is this valid? */
            pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_SESSION_ID,
                              session);
        }
    }

    /* Connect to PulseAudio daemon */
    pa_context *ctx;
    pa_mainloop_api *api;

    pa_threaded_mainloop_lock (mainloop);
    api = pa_threaded_mainloop_get_api (mainloop);
    ctx = pa_context_new_with_proplist (api, ua, props);
    free (ua);
    if (props != NULL)
        pa_proplist_free (props);
    if (unlikely(ctx == NULL))
        goto fail;

    pa_context_set_state_callback (ctx, context_state_cb, mainloop);
    if (pa_context_connect (ctx, NULL, 0, NULL) < 0
     || context_wait (ctx, mainloop))
    {
        vlc_pa_error (obj, "PulseAudio server connection failure", ctx);
        pa_context_unref (ctx);
        goto fail;
    }
    msg_Dbg (obj, "connected %s to %s as client #%"PRIu32,
             pa_context_is_local (ctx) ? "locally" : "remotely",
             pa_context_get_server (ctx), pa_context_get_index (ctx));
    msg_Dbg (obj, "using protocol %"PRIu32", server protocol %"PRIu32,
             pa_context_get_protocol_version (ctx),
             pa_context_get_server_protocol_version (ctx));

    pa_threaded_mainloop_unlock (mainloop);
    *mlp = mainloop;
    return ctx;

fail:
    pa_threaded_mainloop_unlock (mainloop);
    pa_threaded_mainloop_stop (mainloop);
    pa_threaded_mainloop_free (mainloop);
    return NULL;
}
Esempio n. 23
0
void
voice_sink_proplist_update(struct userdata *u, pa_sink *s)
{
  pa_sink *master_sink;
  const char *mode;
  const char *accessory_hwid;

  pa_proplist *p;
  char *hash_str;
  unsigned int hash;
  const char *file;
  char fname[256];
  size_t nbytes;
  const void *data;

  master_sink = voice_get_original_master_sink(u);

  ENTER();

  if (!master_sink)
  {
    pa_log_warn("Original master sink not found, parameters not loaded.");
    return;
  }

  if (!pa_proplist_get(s->proplist, "x-maemo.aep.trace-func", &data, &nbytes))
    memcpy(&u->trace_func, data, sizeof(u->trace_func));

  mode = pa_proplist_gets(s->proplist, PA_NOKIA_PROP_AUDIO_MODE);

  accessory_hwid = pa_proplist_gets(s->proplist,
                                    PA_NOKIA_PROP_AUDIO_ACCESSORY_HWID);

  if (!accessory_hwid || !mode)
    return;

  if (master_sink != s)
  {
    p = pa_proplist_new();
    pa_proplist_sets(p, PA_NOKIA_PROP_AUDIO_MODE, mode);
    pa_proplist_sets(p, PA_NOKIA_PROP_AUDIO_ACCESSORY_HWID, accessory_hwid);
    pa_proplist_update(master_sink->proplist, PA_UPDATE_REPLACE, p);
    pa_proplist_free(p);
  }

  hash_str = pa_sprintf_malloc("%s%s", mode, accessory_hwid);
  hash = pa_idxset_string_hash_func(hash_str);
  pa_xfree(hash_str);

  if (hash == u->mode_accessory_hwid_hash &&
      !voice_pa_proplist_get_bool(master_sink->proplist, "x-maemo.tuning"))
    return;

  u->mode_accessory_hwid_hash = hash;
  file = pa_proplist_gets(master_sink->proplist, "x-maemo.file");

  if (!file)
    file = "/var/lib/pulse-nokia/%s%s.parameters";

  pa_snprintf(fname, sizeof(fname), file, mode);

  pa_log_debug("Loading tuning parameters from file: %s",fname);

  p = pa_nokia_proplist_from_file(fname);

  if (!pa_proplist_contains(p, "x-maemo.aep") )
  {
    pa_log_warn("Parameter file not valid: %s", fname);
    pa_proplist_free(p);
    return;
  }

  u->btmono = FALSE;

  if (!strcmp(mode, "ihf"))
    aep_runtime_switch[3] = 'i';
  else if (!strcmp(mode, "hs"))
    aep_runtime_switch[3] = 't';
  else if (!strcmp(mode, "btmono"))
  {
    aep_runtime_switch[3] = 't';
    u->btmono = TRUE;
  }
  else if (!strcmp(mode, "hp"))
      aep_runtime_switch[3] = 'p';
  else if (!strcmp(mode, "lineout"))
    aep_runtime_switch[3] = 'f';
  else
    aep_runtime_switch[3] = 't';

  if (master_sink == s)
     pa_proplist_update(master_sink->proplist, PA_UPDATE_REPLACE, p);
  else
    pa_sink_update_proplist(master_sink, PA_UPDATE_REPLACE, p);

  pa_proplist_free(p);
  voice_update_parameters(u);

  return;
}