static void packet_test(unsigned npackets, size_t plength, pa_mainloop *ml, pa_pstream *p1, pa_pstream *p2) {
    pa_packet *packet = pa_packet_new(plength);
    unsigned i;
    unsigned psum = 0, totalsum = 0;
    uint8_t *pdata;
    size_t plen;

    pa_log_info("Sending %d packets of length %zd", npackets, plength);
    packets_received = 0;
    packets_checksum = 0;
    packets_length = plength;
    pa_pstream_set_receive_packet_callback(p2, packet_received, NULL);

    pdata = (uint8_t *) pa_packet_data(packet, &plen);
    for (i = 0; i < plen; i++) {
        pdata[i] = i;
        psum += pdata[i];
    }

    for (i = 0; i < npackets; i++) {
        pa_pstream_send_packet(p1, packet, NULL);
        totalsum += psum;
        pa_mainloop_iterate(ml, 0, NULL);
    }

    while (packets_received < npackets)
        pa_mainloop_iterate(ml, 1, NULL);

    fail_unless(packets_checksum == totalsum);
    pa_log_debug("Correct checksum received (%d)", packets_checksum);
    pa_packet_unref(packet);
}
Example #2
0
static int pa_get_devicelist(AudioDeviceInfoList& input)
{
	pa_mainloop *pa_ml;
	pa_mainloop_api *pa_mlapi;
	pa_operation *pa_op;
	pa_context *pa_ctx;

	int state = 0;
	int pa_ready = 0;

	pa_ml = pa_mainloop_new();
	pa_mlapi = pa_mainloop_get_api(pa_ml);
	pa_ctx = pa_context_new(pa_mlapi, "USBqemu-devicelist");

	pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL);

	pa_context_set_state_callback(pa_ctx, pa_context_state_cb, &pa_ready);

	for (;;) {

		if (pa_ready == 0)
		{
			pa_mainloop_iterate(pa_ml, 1, NULL);
			continue;
		}

		// Connection failed
		if (pa_ready == 2)
		{
			pa_context_disconnect(pa_ctx);
			pa_context_unref(pa_ctx);
			pa_mainloop_free(pa_ml);
			return -1;
		}

		switch (state)
		{
			case 0:
				pa_op = pa_context_get_source_info_list(pa_ctx,
						pa_sourcelist_cb,
						&input);
				state++;
				break;
			case 1:
				if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE)
				{
					pa_operation_unref(pa_op);
					pa_context_disconnect(pa_ctx);
					pa_context_unref(pa_ctx);
					pa_mainloop_free(pa_ml);
					return 0;
				}
				break;
			default:
				return -1;
		}
		pa_mainloop_iterate(pa_ml, 1, NULL);
	}
}
void AudioDriverPulseAudio::detect_channels(bool capture) {

	pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map);

	String device = capture ? capture_device_name : device_name;
	if (device == "Default") {
		// Get the default output device name
		pa_status = 0;
		pa_operation *pa_op = pa_context_get_server_info(pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)this);
		if (pa_op) {
			while (pa_status == 0) {
				int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
				if (ret < 0) {
					ERR_PRINT("pa_mainloop_iterate error");
				}
			}

			pa_operation_unref(pa_op);
		} else {
			ERR_PRINT("pa_context_get_server_info error");
		}
	}

	char dev[1024];
	if (device == "Default") {
		strcpy(dev, capture ? capture_default_device.utf8().get_data() : default_device.utf8().get_data());
	} else {
		strcpy(dev, device.utf8().get_data());
	}

	// Now using the device name get the amount of channels
	pa_status = 0;
	pa_operation *pa_op;
	if (capture) {
		pa_op = pa_context_get_source_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_source_info_cb, (void *)this);
	} else {
		pa_op = pa_context_get_sink_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_sink_info_cb, (void *)this);
	}

	if (pa_op) {
		while (pa_status == 0) {
			int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
			if (ret < 0) {
				ERR_PRINT("pa_mainloop_iterate error");
			}
		}

		pa_operation_unref(pa_op);
	} else {
		if (capture) {
			ERR_PRINT("pa_context_get_source_info_by_name error");
		} else {
			ERR_PRINT("pa_context_get_sink_info_by_name error");
		}
	}
}
Example #4
0
int pa_get_devicelist(pa_devicelist_t *output)
{
	pa_mainloop *pa_ml = NULL;
	pa_mainloop_api *pa_mlapi = NULL;
	pa_operation *pa_op = NULL;
	pa_context *pa_ctx = NULL;

	uint8_t state = 0;
	int pa_ready = 0;

	memset(output, 0, sizeof(pa_devicelist_t) * 16);

	if ( (pa_ml = pa_mainloop_new()) == NULL) return -1;
	if ( (pa_mlapi = pa_mainloop_get_api(pa_ml)) == NULL ) return -2;
	if ( (pa_ctx = pa_context_new(pa_mlapi, "test")) == NULL) return -3;

	pa_context_connect(pa_ctx, NULL, 0, NULL);

	pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);

	while (1) {
		if (pa_ready == 0) {
			pa_mainloop_iterate(pa_ml, 1, NULL);
			continue;
		}
		if (pa_ready == 2) {
			pa_context_disconnect(pa_ctx);
			pa_context_unref(pa_ctx);
			pa_mainloop_free(pa_ml);
			return -1;
		}
		switch (state) {
			case 0:
				pa_op = pa_context_get_sink_info_list(pa_ctx, pa_sinklist_cb, output);

				state++;
				break;
			case 1:
				if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
					pa_operation_unref(pa_op);
					pa_context_disconnect(pa_ctx);
					pa_context_unref(pa_ctx);
					pa_mainloop_free(pa_ml);
					return 0;
				}
				break;
			default:
				return -1;
		}
		pa_mainloop_iterate(pa_ml, 1, NULL);
	}
}
Example #5
0
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 (pa_ready == 0) {
            pa_mainloop_iterate(pa_ml, 1, NULL);
            continue;
        }
        if (pa_ready == 2) {
            pa_context_disconnect(pa_ctx);
            pa_context_unref(pa_ctx);
            pa_mainloop_free(pa_ml);
            return -1;
        }
        switch (state) {
            case 0:
                pa_op = pa_context_get_source_output_info_list(pa_ctx, pa_source_output_cb, NULL);
                state++;
                break;
            case 1:
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
                    pa_operation_unref(pa_op);
                    pa_context_disconnect(pa_ctx);
                    pa_context_unref(pa_ctx);
                    pa_mainloop_free(pa_ml);
                    return 0;
                }
                break;
            default:
                fprintf(stderr, "in state %d\n", state);
                return -1;
        }
        pa_mainloop_iterate(pa_ml, 1, NULL);
    }
    return 0;
}
Example #6
0
bool PulseHandler::Init(void)
{
    if (m_initialised)
        return m_valid;
    m_initialised = true;

    // Initialse our connection to the server
    m_loop = pa_mainloop_new();
    if (!m_loop)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get PulseAudio mainloop");
        return m_valid;
    }

    pa_mainloop_api *api = pa_mainloop_get_api(m_loop);
    if (!api)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get PulseAudio api");
        return m_valid;
    }

    if (pa_signal_init(api) != 0)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise signaling");
        return m_valid;
    }

    const char *client = "mythtv";
    m_ctx = pa_context_new(api, client);
    if (!m_ctx)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create context");
        return m_valid;
    }

    // remember which thread created this object for later sanity debugging
    m_thread = QThread::currentThread();

    // we set the callback, connect and then run the main loop 'by hand'
    // until we've successfully connected (or not)
    pa_context_set_state_callback(m_ctx, StatusCallback, this);
    pa_context_connect(m_ctx, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL);
    int ret = 0;
    int tries = 0;
    while ((tries++ < 100) && !IS_READY(m_ctx_state))
    {
        pa_mainloop_iterate(m_loop, 0, &ret);
        usleep(10000);
    }

    if (PA_CONTEXT_READY != m_ctx_state)
    {
        LOG(VB_GENERAL, LOG_ERR, LOC + "Context not ready after 1000ms");
        return m_valid;
    }

    LOG(VB_AUDIO, LOG_INFO, LOC + "Initialised handler");
    m_valid = true;
    return m_valid;
}
Example #7
0
QList<DeviceFinder::Device> PulseDeviceFinder::ListDevices() {
  if (!context_ || pa_context_get_state(context_) != PA_CONTEXT_READY) {
    return QList<Device>();
  }

retry:
  ListDevicesState state;
  pa_context_get_sink_info_list(
      context_, &PulseDeviceFinder::GetSinkInfoCallback, &state);

  forever {
    if (state.finished) {
      return state.devices;
    }

    switch (pa_context_get_state(context_)) {
    case PA_CONTEXT_READY:
      break;
    case PA_CONTEXT_FAILED:
    case PA_CONTEXT_TERMINATED:
      // Maybe pulseaudio died.  Try reconnecting.
      if (Reconnect()) {
        goto retry;
      }
      return state.devices;
    default:
      return state.devices;
    }

    pa_mainloop_iterate(mainloop_, true, nullptr);
  }
}
Example #8
0
/*
 * Initialize pulseAudio
 */
static int init_pa(recorder_context_t *rctx)
{
    pa_mainloop_api *pa_mlapi;
    pa_proplist *ctx_properties = pa_proplist_new();
    pa_proplist *stream_properties = pa_proplist_new();
    int retval = 0;

    rctx->pa_ml = pa_mainloop_new();
    pa_mlapi = pa_mainloop_get_api(rctx->pa_ml);
    rctx->pa_ctx = pa_context_new_with_proplist(pa_mlapi, 
                       "NoApp recorder", ctx_properties);
    pa_context_connect(rctx->pa_ctx, NULL, 0, NULL);

    rctx->pa_ready = 0;
    pa_context_set_state_callback(rctx->pa_ctx, pa_state_cb, rctx);
    while (rctx->pa_ready == 0){
        pa_mainloop_iterate(rctx->pa_ml, 1, NULL);
    }
    if (rctx->pa_ready == 2){
        retval = -1;
        goto exit;
    }

    rctx->recording_stream = pa_stream_new_with_proplist(rctx->pa_ctx,
                                 "NoApp recorder", &rctx->pa_ss, 
                                 NULL, stream_properties);
    retval = pa_stream_connect_record(rctx->recording_stream, NULL, NULL, 0);
    if (retval < 0){
        Log(LOG_ERR, "pa_stream_connect_playback failed\n");
        goto exit;
    }

exit:
    return retval;
}
Example #9
0
bool PulseDeviceFinder::Reconnect() {
  if (context_) {
    pa_context_disconnect(context_);
    pa_context_unref(context_);
  }

  context_ = pa_context_new(pa_mainloop_get_api(mainloop_),
                            "Clementine device finder");
  if (!context_) {
    qLog(Warning) << "Failed to create pulseaudio context";
    return false;
  }

  if (pa_context_connect(context_, nullptr, PA_CONTEXT_NOFLAGS, nullptr) < 0) {
    qLog(Warning) << "Failed to connect pulseaudio context";
    return false;
  }

  // Wait for the context to be connected.
  forever {
    const pa_context_state state = pa_context_get_state(context_);
    if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) {
      qLog(Warning) << "Connection to pulseaudio failed";
      return false;
    }

    if (state == PA_CONTEXT_READY) {
      return true;
    }

    pa_mainloop_iterate(mainloop_, true, nullptr);
  }
}
Error AudioDriverPulseAudio::init() {

	active = false;
	thread_exited = false;
	exit_thread = false;

	mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);

	pa_ml = pa_mainloop_new();
	ERR_FAIL_COND_V(pa_ml == NULL, ERR_CANT_OPEN);

	pa_ctx = pa_context_new(pa_mainloop_get_api(pa_ml), "Godot");
	ERR_FAIL_COND_V(pa_ctx == NULL, ERR_CANT_OPEN);

	pa_ready = 0;
	pa_context_set_state_callback(pa_ctx, pa_state_cb, (void *)this);

	int ret = pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL);
	if (ret < 0) {
		if (pa_ctx) {
			pa_context_unref(pa_ctx);
			pa_ctx = NULL;
		}

		if (pa_ml) {
			pa_mainloop_free(pa_ml);
			pa_ml = NULL;
		}

		return ERR_CANT_OPEN;
	}

	while (pa_ready == 0) {
		pa_mainloop_iterate(pa_ml, 1, NULL);
	}

	if (pa_ready < 0) {
		if (pa_ctx) {
			pa_context_disconnect(pa_ctx);
			pa_context_unref(pa_ctx);
			pa_ctx = NULL;
		}

		if (pa_ml) {
			pa_mainloop_free(pa_ml);
			pa_ml = NULL;
		}

		return ERR_CANT_OPEN;
	}

	Error err = init_device();
	if (err == OK) {
		mutex = Mutex::create();
		thread = Thread::create(AudioDriverPulseAudio::thread_func, this);
	}

	return OK;
}
Example #11
0
/** Wait until the specified operation completes */
static void wait_for_operation(struct pa_operation *o) {
    assert(o && context && mainloop);

    while (pa_operation_get_state(o) == PA_OPERATION_RUNNING)
        pa_mainloop_iterate(mainloop, 1, NULL);

    pa_operation_unref(o);
}
Example #12
0
void* PulseAudio::paLoop(void* data)
      {
      PulseAudio* pa = (PulseAudio*)data;
      pa->runState = 2;
      while (pa->runState == 2)
            pa_mainloop_iterate(pa->pa_ml, 1, NULL);
      pa->runState = 0;
      return 0;
      }
Example #13
0
bool PulseAudio::init(bool)
      {
      pa_ml                     = pa_mainloop_new();
      pa_mainloop_api* pa_mlapi = pa_mainloop_get_api(pa_ml);
      pa_context* pa_ctx        = pa_context_new(pa_mlapi, "MuseScore");
      if (pa_context_connect(pa_ctx, NULL, pa_context_flags_t(0), NULL) != 0)
            qDebug("PulseAudio Context Connect Failed with Error: %s", pa_strerror(pa_context_errno(pa_ctx)));

      int pa_ready = 0;
      pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);

      while (pa_ready == 0)
            pa_mainloop_iterate(pa_ml, 1, NULL);
      if (pa_ready == 2)
            return false;

      ss.rate     = _sampleRate;
      ss.channels = 2;
      ss.format   = PA_SAMPLE_FLOAT32LE;

      pa_stream* playstream = pa_stream_new(pa_ctx, "Playback", &ss, NULL);
      if (!playstream) {
            qDebug("pa_stream_new failed");
            return false;
            }
      pa_stream_set_write_callback(playstream, paCallback, this);

      bufattr.fragsize  = (uint32_t)-1;
      bufattr.maxlength = FRAMES * 2 * sizeof(float);
      bufattr.minreq    = FRAMES * 1 * sizeof(float); // pa_usec_to_bytes(0, &ss);
      bufattr.prebuf    = (uint32_t)-1;
      bufattr.tlength   = bufattr.maxlength;
      int r = pa_stream_connect_playback(playstream, NULL, &bufattr,
         pa_stream_flags_t(PA_STREAM_INTERPOLATE_TIMING
         | PA_STREAM_ADJUST_LATENCY
         | PA_STREAM_AUTO_TIMING_UPDATE),
         NULL, NULL);

      if (r < 0) {
            // Old pulse audio servers don't like the ADJUST_LATENCY flag, so retry without that
            r = pa_stream_connect_playback(playstream, NULL, &bufattr,
               pa_stream_flags_t(PA_STREAM_INTERPOLATE_TIMING
               | PA_STREAM_AUTO_TIMING_UPDATE),
               NULL, NULL);
            }
      if (r < 0) {
            qDebug("pa_stream_connect_playback failed");
            pa_context_disconnect(pa_ctx);
            pa_context_unref(pa_ctx);
            pa_mainloop_free(pa_ml);
            pa_ml = 0;
            return false;
            }
      return true;
      }
Example #14
0
bool PulseHandler::SuspendInternal(bool suspend)
{
    // set everything up...
    if (!Init())
        return false;

    // just in case it all goes pete tong
    if (!is_current_thread(m_thread))
        LOG(VB_AUDIO, LOG_WARNING, LOC +
            "PulseHandler called from a different thread");

    QString action = suspend ? "suspend" : "resume";
    // don't bother to suspend a networked server
    if (!pa_context_is_local(m_ctx))
    {
        LOG(VB_GENERAL, LOG_ERR, LOC +
                "PulseAudio server is remote. No need to " + action);
        return false;
    }

    // create and dispatch 2 operations to suspend or resume all current sinks
    // and all current sources
    m_pending_operations = 2;
    pa_operation *operation_sink =
        pa_context_suspend_sink_by_index(
            m_ctx, PA_INVALID_INDEX, suspend, OperationCallback, this);
    pa_operation_unref(operation_sink);

    pa_operation *operation_source =
        pa_context_suspend_source_by_index(
            m_ctx, PA_INVALID_INDEX, suspend, OperationCallback, this);
    pa_operation_unref(operation_source);

    // run the loop manually and wait for the callbacks
    int count = 0;
    int ret = 0;
    while (m_pending_operations && count++ < 100)
    {
        pa_mainloop_iterate(m_loop, 0, &ret);
        usleep(10000);
    }

    // a failure isn't necessarily disastrous
    if (m_pending_operations)
    {
        m_pending_operations = 0;
        LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to " + action);
        return false;
    }

    // rejoice
    LOG(VB_GENERAL, LOG_INFO, LOC + "PulseAudio " + action + " OK");
    return true;
}
Example #15
0
bool PulseAudio::PulseInit()
{
	m_pa_error = 0;
	m_pa_connected = 0;

	// create pulseaudio main loop and context
	// also register the async state callback which is called when the connection to the pa server has changed
	m_pa_ml = pa_mainloop_new();
	m_pa_mlapi = pa_mainloop_get_api(m_pa_ml);
	m_pa_ctx = pa_context_new(m_pa_mlapi, "dolphin-emu");
	m_pa_error = pa_context_connect(m_pa_ctx, nullptr, PA_CONTEXT_NOFLAGS, nullptr);
	pa_context_set_state_callback(m_pa_ctx, StateCallback, this);

	// wait until we're connected to the pulseaudio server
	while (m_pa_connected == 0 && m_pa_error >= 0)
		m_pa_error = pa_mainloop_iterate(m_pa_ml, 1, nullptr);

	if (m_pa_connected == 2 || m_pa_error < 0)
	{
		ERROR_LOG(AUDIO, "PulseAudio failed to initialize: %s", pa_strerror(m_pa_error));
		return false;
	}

	// create a new audio stream with our sample format
	// also connect the callbacks for this stream
	pa_sample_spec ss;
	ss.format = PA_SAMPLE_S16LE;
	ss.channels = 2;
	ss.rate = m_mixer->GetSampleRate();
	m_pa_s = pa_stream_new(m_pa_ctx, "Playback", &ss, nullptr);
	pa_stream_set_write_callback(m_pa_s, WriteCallback, this);
	pa_stream_set_underflow_callback(m_pa_s, UnderflowCallback, this);

	// connect this audio stream to the default audio playback
	// limit buffersize to reduce latency
	m_pa_ba.fragsize = -1;
	m_pa_ba.maxlength = -1;          // max buffer, so also max latency
	m_pa_ba.minreq = -1;             // don't read every byte, try to group them _a bit_
	m_pa_ba.prebuf = -1;             // start as early as possible
	m_pa_ba.tlength = BUFFER_SIZE;   // designed latency, only change this flag for low latency output
	pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE);
	m_pa_error = pa_stream_connect_playback(m_pa_s, nullptr, &m_pa_ba, flags, nullptr, nullptr);
	if (m_pa_error < 0)
	{
		ERROR_LOG(AUDIO, "PulseAudio failed to initialize: %s", pa_strerror(m_pa_error));
		return false;
	}

	INFO_LOG(AUDIO, "Pulse successfully initialized");
	return true;
}
Example #16
0
void m1sdr_PlayStop(void)
{
	#if 0
	pa_operation *op;
	#endif

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

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

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

	waveLogStop();
	oss_playing = 0;
}
Example #17
0
int start_recording(recorder_context_t *rctx)
{
    int retval = 0;
    time_t current_time;

    Log(LOG_INFO, "Starting recorder.\n");


    if ((retval = init_filenames(rctx)) < 0){
        Log(LOG_ERR, "Failed in the initialization of the recording file.\n");
        goto exit;
    }
    Log(LOG_INFO, "Filenames created.\n");

    if ((retval = init_pa(rctx)) < 0){
        Log(LOG_ERR, "Failed in the initializaion of pulse audio.\n");
        goto exit;
    }
    Log(LOG_INFO, "PulseAudio connected.\n");

    Log(LOG_INFO, "Calibrating threshold.\n");
    printf("*****  ATTENTION  *****\n");
    printf("Keep quiet for the next %d seconds please.\n", QUIET_TIME);
    pa_stream_set_read_callback(rctx->recording_stream, detect_threshold_cb, rctx);
    rctx->timestamp = time(NULL);
    current_time = rctx->timestamp;
#ifdef DEBUG
    threshold_file = fopen("/tmp/threshold.pcm", "wb");
#endif
    while (difftime(current_time, rctx->timestamp) < QUIET_TIME){
        pa_mainloop_iterate(rctx->pa_ml, 0, &retval);
        current_time = time(NULL);
        if (retval < 0){
            Log(LOG_ERR,
                "There was a problem calculating the threshold power.\n");
            goto exit;
        }
    }
    Log(LOG_DEBUG, "Threshold: %f\n", rctx->threshold);

    Log(LOG_INFO, "Entering into the mainloop.\n");
    printf("\nNow you can start talking.\n");
    rctx->timestamp = time(NULL);
    pa_stream_set_read_callback(rctx->recording_stream, stream_request_cb, rctx);
    pa_mainloop_run(rctx->pa_ml, &retval);

exit:
    stop_recording(rctx, false);
    return retval;
}
Example #18
0
void *kradpulse_loop_thread(void *arg) {

    krad_pulse_t *kradpulse = (krad_pulse_t *)arg;

    // Iterate the main loop and go again.  The second argument is whether
    // or not the iteration should block until something is ready to be
    // done.  Set it to zero for non-blocking.

    while (kradpulse->shutdown == 0) {
        pa_mainloop_iterate(kradpulse->pa_ml, 1, NULL);
    }

    return NULL;

}
Example #19
0
// Called on audio thread.
void PulseAudio::SoundLoop()
{
	Common::SetCurrentThreadName("Audio thread - pulse");

	if (PulseInit())
	{
		while (m_run_thread.load() && m_pa_connected == 1 && m_pa_error >= 0)
			m_pa_error = pa_mainloop_iterate(m_pa_ml, 1, nullptr);

		if (m_pa_error < 0)
			ERROR_LOG(AUDIO, "PulseAudio error: %s", pa_strerror(m_pa_error));

		PulseShutdown();
	}
}
Example #20
0
bool PulseAudio::init(bool)
      {
      pa_ml                     = pa_mainloop_new();
      pa_mainloop_api* pa_mlapi = pa_mainloop_get_api(pa_ml);
      pa_context* pa_ctx        = pa_context_new(pa_mlapi, "MuseScore");
      if (pa_context_connect(pa_ctx, NULL, pa_context_flags_t(0), NULL) != 0) {
            qDebug("PulseAudio Context Connect Failed with Error: %s", pa_strerror(pa_context_errno(pa_ctx)));
            return false;
            }

      int pa_ready = 0;
      pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);

      while (pa_ready == 0)
            pa_mainloop_iterate(pa_ml, 1, NULL);
      if (pa_ready == 2)
            return false;

      ss.rate     = _sampleRate;
      ss.channels = 2;
      ss.format   = PA_SAMPLE_FLOAT32LE;

      pa_stream* playstream = pa_stream_new(pa_ctx, "Playback", &ss, NULL);
      if (!playstream) {
            qDebug("pa_stream_new failed: %s", pa_strerror(pa_context_errno(pa_ctx)));
            return false;
            }
      pa_stream_set_write_callback(playstream, paCallback, this);

      bufattr.fragsize  = (uint32_t)-1;
      bufattr.maxlength = FRAMES * 2 * sizeof(float);
      bufattr.minreq    = FRAMES * 1 * sizeof(float); // pa_usec_to_bytes(0, &ss);
      bufattr.prebuf    = (uint32_t)-1;
      bufattr.tlength   = bufattr.maxlength;

      int r = pa_stream_connect_playback(playstream, nullptr, &bufattr,
         PA_STREAM_NOFLAGS, nullptr, nullptr);

      if (r < 0) {
            qDebug("pa_stream_connect_playback failed");
            pa_context_disconnect(pa_ctx);
            pa_context_unref(pa_ctx);
            pa_mainloop_free(pa_ml);
            pa_ml = 0;
            return false;
            }
      return true;
      }
Example #21
0
APULSE_EXPORT
int
pa_mainloop_run(pa_mainloop *m, int *retval)
{
    trace_info("F %s\n", __func__);

    int ret;
    do {
        ret = pa_mainloop_iterate(m, 1, retval);
    } while (ret >= 0 && !m->terminate);

    if (m->terminate) {
        *retval = m->retval;
        return 0;
    }

    return ret;
}
Example #22
0
int pulse_init(struct pulseaudio_t *pulse) {
    enum pa_context_state state = PA_CONTEXT_CONNECTING;

    pulse->mainloop = pa_mainloop_new();
    pulse->cxt = pa_context_new(pa_mainloop_get_api(pulse->mainloop), "pavol");
    pulse->default_sink = NULL;
    pulse->muted = 0;
    pulse->volume = 0;

    pa_context_set_state_callback(pulse->cxt, pulse_connect_state_cb, &state);
    pa_context_connect(pulse->cxt, NULL, PA_CONTEXT_NOFLAGS, NULL);
    while (state != PA_CONTEXT_READY && state != PA_CONTEXT_FAILED)
        pa_mainloop_iterate(pulse->mainloop, 1, NULL);

    if (state != PA_CONTEXT_READY) {
        fprintf(stderr, "failed to connect to pulse daemon: %s\n",
                pa_strerror(pa_context_errno(pulse->cxt)));
        return 1;
    }

    return 0;
}
Example #23
0
/* The implementation of create_output_device_name_list() is based on the
 * example code in
 * http://www.ypass.net/blog/2009/10/
 *    pulseaudio-an-async-example-to-get-device-lists/
 */
mbx_error_code mbx_create_output_device_name_list(char ***dev_names, size_t *n_devs)
{
    pa_mainloop *pa_ml = pa_mainloop_new();
    pa_mainloop_api *pa_mlapi = pa_mainloop_get_api(pa_ml);
    pa_context *pa_ctx = pa_context_new(pa_mlapi, "music box (listing output "
        "devices)");
    pa_operation *pa_op;
    pa_context_state_t pa_context_state = PA_CONTEXT_UNCONNECTED;
    int do_iterate = 1;
    int error = 0;

    pa_context_connect(pa_ctx, NULL, 0, NULL);
    /* The state callback will update the state when we are connected to the
     * PulseAudio server, or if an error occurs. */
    pa_context_set_state_callback(pa_ctx, pa_context_state_cb,
        &pa_context_state);

    while ( do_iterate ) {
        switch ( pa_context_state ) {
            case PA_CONTEXT_UNCONNECTED:
            case PA_CONTEXT_CONNECTING:
            case PA_CONTEXT_AUTHORIZING:
            case PA_CONTEXT_SETTING_NAME:
                pa_mainloop_iterate(pa_ml, 1, NULL); // we must wait.
                break;
            case PA_CONTEXT_READY:
                do_iterate = 0;
                break;
            case PA_CONTEXT_FAILED:
                mbx_log_error(MBX_LOG_AUDIO_OUTPUT, "Connection to PulseAudio server failed: "
                    "%s", pa_strerror(pa_context_errno(pa_ctx)));
                error = 1;
                break;
            case PA_CONTEXT_TERMINATED:
                mbx_log_error(MBX_LOG_AUDIO_OUTPUT, "Connection to PulseAudio server "
                    "terminated unexpectedly.");
                error = 1;
                break;
            default:
                mbx_log_error(MBX_LOG_AUDIO_OUTPUT, "The PulseAudio context has an unexpected "
                    "state: %d", pa_context_state);
                error = 1;
                break;
        }
        if ( error ) {
            do_iterate = 0;
        }
    }
    if ( ! error ) {
        struct list_of_strings result = { NULL, 0, 0 };
        pa_op = pa_context_get_sink_info_list(pa_ctx, pa_sinklist_cb, &result);
        while ( pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING ) {
            pa_mainloop_iterate(pa_ml, 1, NULL); // wait.
        }
        pa_operation_unref(pa_op);
        *dev_names = result.strings;
        *n_devs = result.n_strings;
    }
    pa_context_disconnect(pa_ctx);
    pa_context_unref(pa_ctx);
    pa_mainloop_free(pa_ml);
    return error ? MBX_PULSEAUDIO_ERROR : MBX_SUCCESS;
}
int set_active_port(pa_devicelist_t device, pa_portlist_t port) {
    pa_mainloop *pa_ml;
    pa_mainloop_api *pa_mlapi;
    pa_operation *pa_op;
    pa_context *pa_ctx;
    
    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, "test");
    pa_context_connect(pa_ctx, NULL, 0, NULL);
    pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);
    
    pa_device_port_t dev_port_set;
    dev_port_set.device = device;
    dev_port_set.port = port;
    
    pa_clientlist_t clientlist[30];
    
    int i = 0;
    
    for (;;) {
        // We can't do anything until PA is ready, so just iterate the mainloop
        // and continue
        if (pa_ready == 0) {
            pa_mainloop_iterate(pa_ml, 1, NULL);
            continue;
        }
        // We couldn't get a connection to the server, so exit out
        if (pa_ready == 2) {
            pa_context_disconnect(pa_ctx);
            pa_context_unref(pa_ctx);
            pa_mainloop_free(pa_ml);
            return -1;
        }
        
        switch(state) {
            case 0:
                // Set source or sink
                switch(device.type) {
                    case JOAPA_SOURCE:
                        pa_op = pa_context_set_source_port_by_index(
                                pa_ctx, 
                                device.index, 
                                port.name, 
                                set_active_port_cb, 
                                &dev_port_set);
                        break;
                    case JOAPA_SINK:
                        pa_op = pa_context_set_sink_port_by_index(
                                pa_ctx, 
                                device.index, 
                                port.name, 
                                set_active_port_cb, 
                                &dev_port_set);
                        break;
                }
                state++;
                break;
            case 1:
                // get clients using a source or sink
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
                    pa_operation_unref(pa_op);
                    switch(device.type) {
                        case JOAPA_SOURCE:
                            pa_op = pa_context_get_source_output_info_list(pa_ctx, pa_source_info_cb, &clientlist);
                            break;
                        case JOAPA_SINK:
                            pa_op = pa_context_get_sink_input_info_list(pa_ctx, pa_sink_info_cb, &clientlist);
                            break;
                    }
                    state++;
                }
                break;
            case 2:
                // move the clients to the new source or sink
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
                    pa_operation_unref(pa_op);
                    
                    if(!clientlist[i].initialized) {
                        pa_context_disconnect(pa_ctx);
                        pa_context_unref(pa_ctx);
                        pa_mainloop_free(pa_ml);
                        return 0;
                    }
                    //printf("CLIENT: %d\n", clientlist[i].index);
                    
                    switch(device.type) {
                        case JOAPA_SOURCE:
                            pa_op = pa_context_move_source_output_by_index(
                                    pa_ctx,
                                    clientlist[i].index, 
                                    device.index, 
                                    set_active_port_cb, NULL);
                            break;
                        case JOAPA_SINK:
                            pa_op = pa_context_move_sink_input_by_index(
                                    pa_ctx, 
                                    clientlist[i].index, 
                                    device.index, 
                                    set_active_port_cb, NULL);
                            break;
                    }
                    
                    i++;
                }
                break;
            default:
                fprintf(stderr, "in state %d\n", state);
                return -1;
        }
        pa_mainloop_iterate(pa_ml, 1, NULL);       
    }

}
int pa_get_devicelist(pa_devicelist_t *input, pa_devicelist_t *output) {
    // Define our pulse audio loop and connection variables
    pa_mainloop *pa_ml;
    pa_mainloop_api *pa_mlapi;
    pa_operation *pa_op;
    pa_context *pa_ctx;

    // We'll need these state variables to keep track of our requests
    int state = 0;
    int pa_ready = 0;

    // Initialize our device lists
    memset(input, 0, sizeof(pa_devicelist_t) * 16);
    memset(output, 0, sizeof(pa_devicelist_t) * 16);

    // Create a mainloop API and connection to the default server
    pa_ml = pa_mainloop_new();
    pa_mlapi = pa_mainloop_get_api(pa_ml);
    pa_ctx = pa_context_new(pa_mlapi, "test");

    // This function connects to the pulse server
    pa_context_connect(pa_ctx, NULL, 0, NULL);

    // This function defines a callback so the server will tell us it's state.
    // Our callback will wait for the state to be ready.  The callback will
    // modify the variable to 1 so we know when we have a connection and it's
    // ready.
    // If there's an error, the callback will set pa_ready to 2
    pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready);

    // Now we'll enter into an infinite loop until we get the data we receive
    // or if there's an error
    for (;;) {
        // We can't do anything until PA is ready, so just iterate the mainloop
        // and continue
        if (pa_ready == 0) {
            pa_mainloop_iterate(pa_ml, 1, NULL);
            continue;
        }
        // We couldn't get a connection to the server, so exit out
        if (pa_ready == 2) {
            pa_context_disconnect(pa_ctx);
            pa_context_unref(pa_ctx);
            pa_mainloop_free(pa_ml);
            return -1;
        }
        // At this point, we're connected to the server and ready to make
        // requests
        switch (state) {
            // State 0: we haven't done anything yet
            case 0:
                // This sends an operation to the server.  pa_sinklist_info is
                // our callback function and a pointer to our devicelist will
                // be passed to the callback The operation ID is stored in the
                // pa_op variable
                pa_op = pa_context_get_sink_info_list(pa_ctx,
                        pa_sinklist_cb,
                        output
                        );

                // Update state for next iteration through the loop
                state++;
                break;
            
            case 1:
                // Now we wait for our operation to complete.  When it's
                // complete our pa_output_devicelist is filled out, and we move
                // along to the next state
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
                    pa_operation_unref(pa_op);

                    // Now we perform another operation to get the source
                    // (input device) list just like before.  This time we pass
                    // a pointer to our input structure
                    pa_op = pa_context_get_source_info_list(pa_ctx,
                            pa_sourcelist_cb,
                            input
                            );
                    // Update the state so we know what to do next
                    state++;
                }
                break;
            case 2:
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
                    // Now we're done, clean up and disconnect and return
                    pa_operation_unref(pa_op);
                    pa_context_disconnect(pa_ctx);
                    pa_context_unref(pa_ctx);
                    pa_mainloop_free(pa_ml);
                    return 0;
                }
                break;
            default:
                // We should never see this state
                fprintf(stderr, "in state %d\n", state);
                return -1;
        }
        // Iterate the main loop and go again.  The second argument is whether
        // or not the iteration should block until something is ready to be
        // done.  Set it to zero for non-blocking.
        pa_mainloop_iterate(pa_ml, 1, NULL);
    }
}
Example #26
0
krad_pulse_t *kradpulse_create(krad_audio_t *kradaudio) {


    krad_pulse_t *kradpulse;

    if ((kradpulse = calloc (1, sizeof (krad_pulse_t))) == NULL) {
        fprintf(stderr, "mem alloc fail\n");
        exit (1);
    }

    kradpulse->kradaudio = kradaudio;


    kradpulse->samples[0] = malloc(24 * 8192);
    kradpulse->samples[1] = malloc(24 * 8192);
    kradpulse->interleaved_samples = malloc(48 * 8192);

    kradpulse->capture_samples[0] = malloc(24 * 8192);
    kradpulse->capture_samples[1] = malloc(24 * 8192);
    kradpulse->capture_interleaved_samples = malloc(48 * 8192);

    kradpulse->latency = 20000; // start latency in micro seconds
    kradpulse->underflows = 0;
    kradpulse->pa_ready = 0;
    kradpulse->retval = 0;

    // Create a mainloop API and connection to the default server
    kradpulse->pa_ml = pa_mainloop_new();
    kradpulse->pa_mlapi = pa_mainloop_get_api(kradpulse->pa_ml);
    kradpulse->pa_ctx = pa_context_new(kradpulse->pa_mlapi, kradpulse->kradaudio->name);

    pa_context_connect(kradpulse->pa_ctx, NULL, 0, NULL);

    // This function defines a callback so the server will tell us it's state.
    // Our callback will wait for the state to be ready.  The callback will
    // modify the variable to 1 so we know when we have a connection and it's
    // ready.
    // If there's an error, the callback will set pa_ready to 2
    pa_context_set_state_callback(kradpulse->pa_ctx, kradpulse_state_cb, kradpulse);

    // We can't do anything until PA is ready, so just iterate the mainloop
    // and continue
    while (kradpulse->pa_ready == 0) {
        pa_mainloop_iterate(kradpulse->pa_ml, 1, NULL);
    }

    if (kradpulse->pa_ready == 2) {
        kradpulse->retval = -1;
        printf("pulseaudio fail\n");
        exit(1);
    }

    kradpulse->ss.rate = 44100;
    kradpulse->ss.channels = 2;
    kradpulse->ss.format = PA_SAMPLE_FLOAT32LE;

    kradpulse->bufattr.fragsize = (uint32_t)-1;
    kradpulse->bufattr.maxlength = pa_usec_to_bytes(kradpulse->latency, &kradpulse->ss);
    kradpulse->bufattr.minreq = pa_usec_to_bytes(0, &kradpulse->ss);
    kradpulse->bufattr.prebuf = (uint32_t)-1;
    kradpulse->bufattr.tlength = pa_usec_to_bytes(kradpulse->latency, &kradpulse->ss);

    if ((kradaudio->direction == KOUTPUT) || (kradaudio->direction == KDUPLEX)) {
        kradpulse->playstream = pa_stream_new(kradpulse->pa_ctx, "Playback", &kradpulse->ss, NULL);

        if (!kradpulse->playstream) {
            printf("playback pa_stream_new failed\n");
            exit(1);
        }

        pa_stream_set_write_callback(kradpulse->playstream, kradpulse_playback_cb, kradpulse);
        pa_stream_set_underflow_callback(kradpulse->playstream, kradpulse_stream_underflow_cb, kradpulse);

        kradpulse->r = pa_stream_connect_playback(kradpulse->playstream, NULL, &kradpulse->bufattr,
                       PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);

        if (kradpulse->r < 0) {
            printf("pa_stream_connect_playback failed\n");
            kradpulse->retval = -1;
            printf("pulseaudio fail\n");
            exit(1);
        }

    }

    if ((kradaudio->direction == KINPUT) || (kradaudio->direction == KDUPLEX)) {
        kradpulse->capturestream = pa_stream_new(kradpulse->pa_ctx, "Capture", &kradpulse->ss, NULL);

        if (!kradpulse->capturestream) {
            printf("capture pa_stream_new failed\n");
            exit(1);
        }


        pa_stream_set_read_callback(kradpulse->capturestream, kradpulse_capture_cb, kradpulse);
        pa_stream_set_underflow_callback(kradpulse->capturestream, kradpulse_stream_underflow_cb, kradpulse);

        kradpulse->r = pa_stream_connect_record(kradpulse->capturestream, NULL, &kradpulse->bufattr, PA_STREAM_NOFLAGS );

        if (kradpulse->r < 0) {
            printf("pa_stream_connect_capture failed\n");
            kradpulse->retval = -1;
            printf("pulseaudio fail\n");
            exit(1);
        }

    }


    kradaudio->sample_rate = kradpulse->ss.rate;


    pthread_create( &kradpulse->loop_thread, NULL, kradpulse_loop_thread, kradpulse);

    return kradpulse;

}
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;
}
Example #28
0
void mexFunction(int nlhs, mxArray *plhs[],
    int nrhs, const mxArray *prhs[])
{
    // We'll need these state variables to keep track of our requests
    int pa_ready = 0;
    int pa_conn = 0;
    int fork_id = 0;
    
    // Create a mainloop API and connection to the default server
    pa_ptrs.pa_ss.format = PA_SAMPLE_S16NE;
    pa_ptrs.pa_ss.rate = 22050;
    pa_ptrs.pa_ss.channels = 1;
    pa_ptrs.pa_ml = pa_mainloop_new();
    pa_ptrs.pa_mlapi = pa_mainloop_get_api(pa_ptrs.pa_ml);
    pa_ptrs.pa_ctx = pa_context_new(pa_ptrs.pa_mlapi, "test");

    // This function connects to the pulse server
    pa_context_connect(pa_ptrs.pa_ctx, NULL, 0, NULL);

    // This function defines a callback so the server will tell us it's state.
    // Our callback will wait for the state to be ready.  The callback will
    // modify the variable to 1 so we know when we have a connection and it's
    // ready.
    // If there's an error, the callback will set pa_ready to 2
    pa_context_set_state_callback(pa_ptrs.pa_ctx, pa_state_cb, &pa_ready);

    for (int i=0;pa_ready == 0 && i<1000;i++) {
        pa_mainloop_iterate(pa_ptrs.pa_ml, 1, NULL);
    }

    if (pa_ready == 2 || pa_ready == 0) {
            pa_context_disconnect(pa_ptrs.pa_ctx);
            pa_context_unref(pa_ptrs.pa_ctx);
            pa_mainloop_free(pa_ptrs.pa_ml);
            printf("Error");
            return;
    }

    // At this point, we're connected to the server and ready to make
	// requests
    printf("Context connected to PA-daemon\n");

    
    pa_ptrs.pa_s = pa_stream_new(pa_ptrs.pa_ctx,"FooStream",&pa_ptrs.pa_ss,NULL);
    pa_stream_connect_playback(pa_ptrs.pa_s, // The stream to connect to a sink 
            NULL, // Name of the sink to connect to, or NULL for default 
            NULL, // Buffering attributes, or NULL for default 
            PA_STREAM_NOFLAGS, // Additional flags, or 0 for default
            NULL, // Initial volume, or NULL for default 
            NULL // Synchronize this stream with the specified one, or NULL for a standalone stream
            );
    pa_stream_set_state_callback(pa_ptrs.pa_s,pa_stream_cb,&pa_conn);
    
    /* Wait for connection or timeout */
    for (int i=0;pa_conn == 0 && i<1000;i++) {
        pa_mainloop_iterate(pa_ptrs.pa_ml,1,NULL);
        
    }

    if (pa_conn == 2 || pa_conn == 0) {
            pa_stream_disconnect(pa_ptrs.pa_s);
            pa_context_disconnect(pa_ptrs.pa_ctx);
            pa_context_unref(pa_ptrs.pa_ctx);
            pa_mainloop_free(pa_ptrs.pa_ml);
            printf("Error");
            return;
    }
    
    mexPrintf("Stream connected to PA-daemon\n");
    
    plhs[0]=mxCreateNumericMatrix(1,1,mxUINT64_CLASS,mxREAL);
    uint64_t *ptr = (uint64_t)mxGetData(plhs[0]);
    *ptr = &pa_ptrs;
}
Example #29
0
int main(int argc, char *const *argv) {
    static const char *context_name = "i3blocks-pulse-volume";
    static const char *usage_str = "Usage: %s [-h] [-d] [-s INDEX] [-m FUNC]\n"
            "Options:\n"
            "  -s INDEX: pulseaudio sink index on which to wait for "
            "changes (default: 0)\n"
            "  -m FUNC : function used to compute the displayed volume value\n"
            "            in there are multiple channels (eg. left/right):\n"
            "             * avg: use average volume of all channels (default)\n"
            "             * min: use minimum volume of all channels\n"
            "             * max: use maximum volume of all channels\n"
            "  -d      : use decibel notation instead of 0-100 percentage; "
            "the sink may\n"
            "            not support this feature\n";

    options_t options;
    options.calculator = pa_cvolume_avg;
    options.use_decibel = 0;
    options.observed_index = 0;

    sink_info_data_t sink_info_data;
    sink_info_data.sink_ready = 0;
    sink_info_data.sink_changed = 0;

    pa_mainloop *pa_ml = NULL;
    pa_mainloop_api *pa_ml_api = NULL;
    pa_operation *pa_op = NULL;
    pa_context *pa_ctx = NULL;

    enum state_t state = FIRST_SINK_INFO;
    int pa_ready = CONN_WAIT;

    int opt;
    while ((opt = getopt(argc, argv, "m:s:dh")) != -1) {
        if (opt == 'm') {
            if (strcmp(optarg, "min") == 0) {
                options.calculator = pa_cvolume_min;
            } else if (strcmp(optarg, "max") == 0) {
                options.calculator = pa_cvolume_max;
            } else if (strcmp(optarg, "avg") == 0) {
                options.calculator = pa_cvolume_avg;
            } else {
                fprintf(stderr, usage_str, argv[0]);
                return 1;
            }
        } else if (opt == 's') {
            // Parse observed sink index
            errno = 0;
            char *endptr;
            uint32_t *oind = &options.observed_index;
            *oind = strtoul(optarg, &endptr, 10);
            if ((errno == ERANGE) || (errno != 0 && *oind == 0) ||
                endptr == optarg) {
                fprintf(stderr, "%s: invalid sink index: %s\n", argv[0],
                        optarg);
                fprintf(stderr, usage_str, argv[0]);
                return 1;
            }
        } else if (opt == 'd') {
            options.use_decibel = 1;
        } else if (opt == 'h') {
            fprintf(stderr, usage_str, argv[0]);
            return 0;
        } else {
            fprintf(stderr, usage_str, argv[0]);
            return 1;
        }
    }

    // Needed to filter out sink in callbacks
    sink_info_data.observed_index = options.observed_index;

    if ((pa_ml = pa_mainloop_new()) == NULL) {
        fprintf(stderr, "error: failed to allocate pulseaudio mainloop.\n");
        return 2;
    }
    if ((pa_ml_api = pa_mainloop_get_api(pa_ml)) == NULL) {
        fprintf(stderr, "error: failed to allocate pulseaudio mainloop API.\n");
        return 3;
    }
    if ((pa_ctx = pa_context_new(pa_ml_api, context_name)) == NULL) {
        fprintf(stderr, "error: failed to allocate pulseaudio context.\n");
        return 4;
    }

    if (pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFAIL, NULL) < 0) {
        fprintf(stderr, "error: failed to connect to pulseaudio context: %s\n",
                pa_strerror(pa_context_errno(pa_ctx)));
        return 5;
    }

    pa_context_set_state_callback(pa_ctx, state_cb, &pa_ready);
    pa_context_set_subscribe_callback(pa_ctx, subscribe_cb, &sink_info_data);

    while (1) {
        if (pa_ready == CONN_WAIT) {
            pa_mainloop_iterate(pa_ml, 1, NULL);
            continue;
        }

        if (pa_ready == CONN_FAILED) {
            pa_context_disconnect(pa_ctx);
            pa_context_unref(pa_ctx);
            pa_mainloop_free(pa_ml);
            fprintf(stderr,
                    "error: failed to connect to pulseaudio context.\n");
            return 6;
        }

        // Main loop automaton
        switch (state) {
            case FIRST_SINK_INFO:
                // First run
                pa_op = pa_context_get_sink_info_by_index(pa_ctx,
                            options.observed_index,
                            sink_info_cb, &sink_info_data);
                state = SUBSCRIBE;
                break;
            case SUBSCRIBE:
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
                    pa_operation_unref(pa_op);
                    if (!sink_info_data.sink_ready) {
                        fprintf(stderr, "error: sink %u does not exist.\n",
                                options.observed_index);
                        pa_context_disconnect(pa_ctx);
                        pa_context_unref(pa_ctx);
                        pa_mainloop_free(pa_ml);
                        return 7;
                    }
                    if (options.use_decibel &&
                        !sink_info_data.sink.can_decibel) {
                        fprintf(stderr,
                                "error: sink %u does not support decibel; "
                                "try without `-d`.\n",
                                options.observed_index);
                        pa_context_disconnect(pa_ctx);
                        pa_context_unref(pa_ctx);
                        pa_mainloop_free(pa_ml);
                        return 8;
                    }
                    // Show volume once at start
                    show_volume(&sink_info_data.sink, &options);
                    // Subsequent runs: wait for changes
                    pa_op = pa_context_subscribe(pa_ctx,
                                                 PA_SUBSCRIPTION_MASK_SINK,
                                                 NULL, &sink_info_data);
                    state = SUBSCRIBED;
                }
                break;
            case SUBSCRIBED:
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
                    pa_operation_unref(pa_op);
                    state = WAIT_FOR_CHANGE;
                }
                break;
            case WAIT_FOR_CHANGE:
                if (sink_info_data.sink_changed) {
                    sink_info_data.sink_changed = 0;
                    pa_op = pa_context_get_sink_info_by_index(pa_ctx,
                                options.observed_index, sink_info_cb,
                                &sink_info_data);
                    state = SHOW_CHANGE;
                }
                break;
            case SHOW_CHANGE:
                if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) {
                    pa_operation_unref(pa_op);
                    show_volume(&sink_info_data.sink, &options);
                    state = WAIT_FOR_CHANGE;
                }
                break;
            default:
                return 7;
        }
        pa_mainloop_iterate(pa_ml, 1, NULL);
    }
}
static void thread_func(void *userdata) {
    struct userdata *u = userdata;
    pa_proplist *proplist;
    pa_assert(u);

    pa_log_debug("Thread starting up");
    pa_thread_mq_install(u->thread_mq);

    proplist = tunnel_new_proplist(u);
    u->context = pa_context_new_with_proplist(u->thread_mainloop_api,
                                              "PulseAudio",
                                              proplist);
    pa_proplist_free(proplist);

    if (!u->context) {
        pa_log("Failed to create libpulse context");
        goto fail;
    }

    if (u->cookie_file && pa_context_load_cookie_from_file(u->context, u->cookie_file) != 0) {
        pa_log_error("Can not load cookie file!");
        goto fail;
    }

    pa_context_set_state_callback(u->context, context_state_cb, u);
    if (pa_context_connect(u->context,
                           u->remote_server,
                           PA_CONTEXT_NOAUTOSPAWN,
                           NULL) < 0) {
        pa_log("Failed to connect libpulse context");
        goto fail;
    }

    for (;;) {
        int ret;

        if (pa_mainloop_iterate(u->thread_mainloop, 1, &ret) < 0) {
            if (ret == 0)
                goto finish;
            else
                goto fail;
        }

        if (PA_UNLIKELY(u->sink->thread_info.rewind_requested))
            pa_sink_process_rewind(u->sink, 0);

        if (u->connected &&
                pa_stream_get_state(u->stream) == PA_STREAM_READY &&
                PA_SINK_IS_LINKED(u->sink->thread_info.state)) {
            size_t writable;

            writable = pa_stream_writable_size(u->stream);
            if (writable > 0) {
            
                if(u->transcode.encoding != -1) {
                         pa_memchunk memchunk;
                         const void *p;
                         size_t nbBytes;
                         unsigned char *cbits;
                         
                         pa_sink_render_full(u->sink, u->transcode.frame_size*u->transcode.channels*u->transcode.sample_size, &memchunk);
                           
                         pa_assert(memchunk.length > 0);
                         pa_assert(memchunk.length >=  u->transcode.frame_size*u->transcode.channels);
                         
                         
                         pa_log_debug("received memchunk length: %zu bytes", memchunk.length );
                         /* we have new data to write */
                         p = pa_memblock_acquire(memchunk.memblock);
   
                         nbBytes = pa_transcode_encode(&u->transcode, (uint8_t*) p + memchunk.index, &cbits);
                         pa_log_debug("encoded length: %zu bytes", nbBytes);
                                                        
                         /* TODO: Use pa_stream_begin_write() to reduce copying. */
                         ret = pa_stream_write_compressed(u->stream,
                                               (uint8_t*) cbits,
                                               nbBytes,
                                               NULL,     /**< A cleanup routine for the data or NULL to request an internal copy */
                                               0,        /** offset */
                                              PA_SEEK_RELATIVE, u->transcode.frame_size*u->transcode.channels*u->transcode.sample_size);
                         pa_memblock_release(memchunk.memblock);
                         pa_memblock_unref(memchunk.memblock);
                         if(nbBytes > 0) free(cbits);
                         
                         if (ret != 0) {
                             pa_log_error("Could not write data into the stream ... ret = %i", ret);
                             u->thread_mainloop_api->quit(u->thread_mainloop_api, TUNNEL_THREAD_FAILED_MAINLOOP);
                         }
                }
                else { 
                         pa_memchunk memchunk;
                         const void *p;

                         pa_sink_render_full(u->sink, writable, &memchunk);

                         pa_assert(memchunk.length > 0);

                         /* we have new data to write */
                         p = pa_memblock_acquire(memchunk.memblock);
                         /* TODO: Use pa_stream_begin_write() to reduce copying. */
                         ret = pa_stream_write(u->stream,
                                               (uint8_t*) p + memchunk.index,
                                               memchunk.length,
                                               NULL,     /**< A cleanup routine for the data or NULL to request an internal copy */
                                               0,        /** offset */
                                               PA_SEEK_RELATIVE);
                         pa_memblock_release(memchunk.memblock);
                         pa_memblock_unref(memchunk.memblock);

                         if (ret != 0) {
                             pa_log_error("Could not write data into the stream ... ret = %i", ret);
                             u->thread_mainloop_api->quit(u->thread_mainloop_api, TUNNEL_THREAD_FAILED_MAINLOOP);
                         }
                
                }

            }
        }
    }
fail:
    pa_asyncmsgq_post(u->thread_mq->outq, PA_MSGOBJECT(u->module->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
    pa_asyncmsgq_wait_for(u->thread_mq->inq, PA_MESSAGE_SHUTDOWN);

finish:
    if (u->stream) {
        pa_stream_disconnect(u->stream);
        pa_stream_unref(u->stream);
        u->stream = NULL;
    }

    if (u->context) {
        pa_context_disconnect(u->context);
        pa_context_unref(u->context);
        u->context = NULL;
    }

    pa_log_debug("Thread shutting down");
}