20#include <freerdp/config.h> 
   29#include <pulse/pulseaudio.h> 
   31#include "tsmf_audio.h" 
   35  ITSMFAudioDevice iface;
 
   38  pa_threaded_mainloop* mainloop;
 
   40  pa_sample_spec sample_spec;
 
   42} TSMFPulseAudioDevice;
 
   44static void tsmf_pulse_context_state_callback(pa_context* context, 
void* userdata)
 
   46  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)userdata;
 
   47  pa_context_state_t state = pa_context_get_state(context);
 
   51    case PA_CONTEXT_READY:
 
   52      DEBUG_TSMF(
"PA_CONTEXT_READY");
 
   53      pa_threaded_mainloop_signal(pulse->mainloop, 0);
 
   56    case PA_CONTEXT_FAILED:
 
   57    case PA_CONTEXT_TERMINATED:
 
   58      DEBUG_TSMF(
"state %d", state);
 
   59      pa_threaded_mainloop_signal(pulse->mainloop, 0);
 
   63      DEBUG_TSMF(
"state %d", state);
 
   68static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse)
 
   70  pa_context_state_t state = PA_CONTEXT_FAILED;
 
   75  if (pa_context_connect(pulse->context, NULL, 0, NULL))
 
   77    WLog_ERR(TAG, 
"pa_context_connect failed (%d)", pa_context_errno(pulse->context));
 
   81  pa_threaded_mainloop_lock(pulse->mainloop);
 
   83  if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
 
   85    pa_threaded_mainloop_unlock(pulse->mainloop);
 
   86    WLog_ERR(TAG, 
"pa_threaded_mainloop_start failed (%d)", pa_context_errno(pulse->context));
 
   92    state = pa_context_get_state(pulse->context);
 
   94    if (state == PA_CONTEXT_READY)
 
   97    if (!PA_CONTEXT_IS_GOOD(state))
 
   99      DEBUG_TSMF(
"bad context state (%d)", pa_context_errno(pulse->context));
 
  103    pa_threaded_mainloop_wait(pulse->mainloop);
 
  106  pa_threaded_mainloop_unlock(pulse->mainloop);
 
  108  if (state == PA_CONTEXT_READY)
 
  110    DEBUG_TSMF(
"connected");
 
  115    pa_context_disconnect(pulse->context);
 
  120static BOOL tsmf_pulse_open(ITSMFAudioDevice* audio, 
const char* device)
 
  122  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio;
 
  126    strncpy(pulse->device, device, 
sizeof(pulse->device) - 1);
 
  129  pulse->mainloop = pa_threaded_mainloop_new();
 
  131  if (!pulse->mainloop)
 
  133    WLog_ERR(TAG, 
"pa_threaded_mainloop_new failed");
 
  137  pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), 
"freerdp");
 
  141    WLog_ERR(TAG, 
"pa_context_new failed");
 
  145  pa_context_set_state_callback(pulse->context, tsmf_pulse_context_state_callback, pulse);
 
  147  if (!tsmf_pulse_connect(pulse))
 
  149    WLog_ERR(TAG, 
"tsmf_pulse_connect failed");
 
  153  DEBUG_TSMF(
"open device %s", pulse->device);
 
  157static void tsmf_pulse_stream_success_callback(pa_stream* stream, 
int success, 
void* userdata)
 
  159  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)userdata;
 
  160  pa_threaded_mainloop_signal(pulse->mainloop, 0);
 
  163static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice* pulse, pa_operation* operation)
 
  165  if (operation == NULL)
 
  168  while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
 
  170    pa_threaded_mainloop_wait(pulse->mainloop);
 
  173  pa_operation_unref(operation);
 
  176static void tsmf_pulse_stream_state_callback(pa_stream* stream, 
void* userdata)
 
  178  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)userdata;
 
  181  pa_stream_state_t state = pa_stream_get_state(stream);
 
  185    case PA_STREAM_READY:
 
  186      DEBUG_TSMF(
"PA_STREAM_READY");
 
  187      pa_threaded_mainloop_signal(pulse->mainloop, 0);
 
  190    case PA_STREAM_FAILED:
 
  191    case PA_STREAM_TERMINATED:
 
  192      DEBUG_TSMF(
"state %d", state);
 
  193      pa_threaded_mainloop_signal(pulse->mainloop, 0);
 
  197      DEBUG_TSMF(
"state %d", state);
 
  202static void tsmf_pulse_stream_request_callback(pa_stream* stream, 
size_t length, 
void* userdata)
 
  204  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)userdata;
 
  205  DEBUG_TSMF(
"%" PRIdz 
"", length);
 
  206  pa_threaded_mainloop_signal(pulse->mainloop, 0);
 
  209static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice* pulse)
 
  211  if (!pulse->context || !pulse->stream)
 
  215  pa_threaded_mainloop_lock(pulse->mainloop);
 
  216  pa_stream_set_write_callback(pulse->stream, NULL, NULL);
 
  217  tsmf_pulse_wait_for_operation(
 
  218      pulse, pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
 
  219  pa_stream_disconnect(pulse->stream);
 
  220  pa_stream_unref(pulse->stream);
 
  221  pulse->stream = NULL;
 
  222  pa_threaded_mainloop_unlock(pulse->mainloop);
 
  226static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse)
 
  228  pa_stream_state_t state = PA_STREAM_FAILED;
 
  229  pa_buffer_attr buffer_attr = { 0 };
 
  235  pa_threaded_mainloop_lock(pulse->mainloop);
 
  236  pulse->stream = pa_stream_new(pulse->context, 
"freerdp", &pulse->sample_spec, NULL);
 
  240    pa_threaded_mainloop_unlock(pulse->mainloop);
 
  241    WLog_ERR(TAG, 
"pa_stream_new failed (%d)", pa_context_errno(pulse->context));
 
  245  pa_stream_set_state_callback(pulse->stream, tsmf_pulse_stream_state_callback, pulse);
 
  246  pa_stream_set_write_callback(pulse->stream, tsmf_pulse_stream_request_callback, pulse);
 
  247  buffer_attr.maxlength = (uint32_t)pa_usec_to_bytes(500000, &pulse->sample_spec);
 
  248  buffer_attr.tlength = (uint32_t)pa_usec_to_bytes(250000, &pulse->sample_spec);
 
  249  buffer_attr.prebuf = (UINT32)-1;
 
  250  buffer_attr.minreq = (UINT32)-1;
 
  251  buffer_attr.fragsize = (UINT32)-1;
 
  253  if (pa_stream_connect_playback(
 
  254          pulse->stream, pulse->device[0] ? pulse->device : NULL, &buffer_attr,
 
  255          PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE,
 
  258    pa_threaded_mainloop_unlock(pulse->mainloop);
 
  259    WLog_ERR(TAG, 
"pa_stream_connect_playback failed (%d)", pa_context_errno(pulse->context));
 
  265    state = pa_stream_get_state(pulse->stream);
 
  267    if (state == PA_STREAM_READY)
 
  270    if (!PA_STREAM_IS_GOOD(state))
 
  272      WLog_ERR(TAG, 
"bad stream state (%d)", pa_context_errno(pulse->context));
 
  276    pa_threaded_mainloop_wait(pulse->mainloop);
 
  279  pa_threaded_mainloop_unlock(pulse->mainloop);
 
  281  if (state == PA_STREAM_READY)
 
  283    DEBUG_TSMF(
"connected");
 
  288    tsmf_pulse_close_stream(pulse);
 
  293static BOOL tsmf_pulse_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels,
 
  294                                  UINT32 bits_per_sample)
 
  296  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio;
 
  297  DEBUG_TSMF(
"sample_rate %" PRIu32 
" channels %" PRIu32 
" bits_per_sample %" PRIu32 
"",
 
  298             sample_rate, channels, bits_per_sample);
 
  299  pulse->sample_spec.rate = sample_rate;
 
  301  WINPR_ASSERT(channels <= UINT8_MAX);
 
  302  pulse->sample_spec.channels = (uint8_t)channels;
 
  303  pulse->sample_spec.format = PA_SAMPLE_S16LE;
 
  304  return tsmf_pulse_open_stream(pulse);
 
  307static BOOL tsmf_pulse_play(ITSMFAudioDevice* audio, 
const BYTE* data, UINT32 data_size)
 
  309  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio;
 
  310  const BYTE* src = NULL;
 
  313  DEBUG_TSMF(
"data_size %" PRIu32 
"", data_size);
 
  317    pa_threaded_mainloop_lock(pulse->mainloop);
 
  320    while (data_size > 0)
 
  322      while ((len = pa_stream_writable_size(pulse->stream)) == 0)
 
  324        DEBUG_TSMF(
"waiting");
 
  325        pa_threaded_mainloop_wait(pulse->mainloop);
 
  328      if (len == (
size_t)-1)
 
  334      ret = pa_stream_write(pulse->stream, src, len, NULL, 0LL, PA_SEEK_RELATIVE);
 
  338        DEBUG_TSMF(
"pa_stream_write failed (%d)", pa_context_errno(pulse->context));
 
  346    pa_threaded_mainloop_unlock(pulse->mainloop);
 
  352static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice* audio)
 
  356  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio;
 
  358  if (pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0)
 
  360    latency = ((UINT64)usec) * 10LL;
 
  366static BOOL tsmf_pulse_flush(ITSMFAudioDevice* audio)
 
  368  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio;
 
  369  pa_threaded_mainloop_lock(pulse->mainloop);
 
  370  tsmf_pulse_wait_for_operation(
 
  371      pulse, pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
 
  372  pa_threaded_mainloop_unlock(pulse->mainloop);
 
  376static void tsmf_pulse_free(ITSMFAudioDevice* audio)
 
  378  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)audio;
 
  380  tsmf_pulse_close_stream(pulse);
 
  384    pa_threaded_mainloop_stop(pulse->mainloop);
 
  389    pa_context_disconnect(pulse->context);
 
  390    pa_context_unref(pulse->context);
 
  391    pulse->context = NULL;
 
  396    pa_threaded_mainloop_free(pulse->mainloop);
 
  397    pulse->mainloop = NULL;
 
  403FREERDP_ENTRY_POINT(UINT VCAPITYPE pulse_freerdp_tsmf_client_audio_subsystem_entry(
void* ptr))
 
  405  ITSMFAudioDevice** sptr = (ITSMFAudioDevice**)ptr;
 
  409  TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*)calloc(1, 
sizeof(TSMFPulseAudioDevice));
 
  412    return ERROR_OUTOFMEMORY;
 
  414  pulse->iface.Open = tsmf_pulse_open;
 
  415  pulse->iface.SetFormat = tsmf_pulse_set_format;
 
  416  pulse->iface.Play = tsmf_pulse_play;
 
  417  pulse->iface.GetLatency = tsmf_pulse_get_latency;
 
  418  pulse->iface.Flush = tsmf_pulse_flush;
 
  419  pulse->iface.Free = tsmf_pulse_free;
 
  420  *sptr = &pulse->iface;
 
  421  return CHANNEL_RC_OK;