|
|
@@ -24,6 +24,7 @@ |
|
|
#include "libavutil/attributes.h" |
|
|
#include "libavutil/attributes.h" |
|
|
#include "libavutil/avstring.h" |
|
|
#include "libavutil/avstring.h" |
|
|
#include "libavutil/mem.h" |
|
|
#include "libavutil/mem.h" |
|
|
|
|
|
#include "libavutil/avassert.h" |
|
|
|
|
|
|
|
|
pa_sample_format_t av_cold ff_codec_id_to_pulse_format(enum AVCodecID codec_id) |
|
|
pa_sample_format_t av_cold ff_codec_id_to_pulse_format(enum AVCodecID codec_id) |
|
|
{ |
|
|
{ |
|
|
@@ -73,6 +74,64 @@ static void pa_state_cb(pa_context *c, void *userdata) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void ff_pulse_audio_disconnect_context(pa_mainloop **pa_ml, pa_context **pa_ctx) |
|
|
|
|
|
{ |
|
|
|
|
|
av_assert0(pa_ml); |
|
|
|
|
|
av_assert0(pa_ctx); |
|
|
|
|
|
|
|
|
|
|
|
if (*pa_ctx) { |
|
|
|
|
|
pa_context_set_state_callback(*pa_ctx, NULL, NULL); |
|
|
|
|
|
pa_context_disconnect(*pa_ctx); |
|
|
|
|
|
pa_context_unref(*pa_ctx); |
|
|
|
|
|
} |
|
|
|
|
|
if (*pa_ml) |
|
|
|
|
|
pa_mainloop_free(*pa_ml); |
|
|
|
|
|
*pa_ml = NULL; |
|
|
|
|
|
*pa_ctx = NULL; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int ff_pulse_audio_connect_context(pa_mainloop **pa_ml, pa_context **pa_ctx, |
|
|
|
|
|
const char *server, const char *description) |
|
|
|
|
|
{ |
|
|
|
|
|
int ret; |
|
|
|
|
|
pa_mainloop_api *pa_mlapi = NULL; |
|
|
|
|
|
enum PulseAudioContextState context_state = PULSE_CONTEXT_INITIALIZING; |
|
|
|
|
|
|
|
|
|
|
|
av_assert0(pa_ml); |
|
|
|
|
|
av_assert0(pa_ctx); |
|
|
|
|
|
|
|
|
|
|
|
*pa_ml = NULL; |
|
|
|
|
|
*pa_ctx = NULL; |
|
|
|
|
|
|
|
|
|
|
|
if (!(*pa_ml = pa_mainloop_new())) |
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
if (!(pa_mlapi = pa_mainloop_get_api(*pa_ml))) { |
|
|
|
|
|
ret = AVERROR_EXTERNAL; |
|
|
|
|
|
goto fail; |
|
|
|
|
|
} |
|
|
|
|
|
if (!(*pa_ctx = pa_context_new(pa_mlapi, description))) { |
|
|
|
|
|
ret = AVERROR(ENOMEM); |
|
|
|
|
|
goto fail; |
|
|
|
|
|
} |
|
|
|
|
|
pa_context_set_state_callback(*pa_ctx, pa_state_cb, &context_state); |
|
|
|
|
|
if (pa_context_connect(*pa_ctx, server, 0, NULL) < 0) { |
|
|
|
|
|
ret = AVERROR_EXTERNAL; |
|
|
|
|
|
goto fail; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while (context_state == PULSE_CONTEXT_INITIALIZING) |
|
|
|
|
|
pa_mainloop_iterate(*pa_ml, 1, NULL); |
|
|
|
|
|
if (context_state == PULSE_CONTEXT_FINISHED) { |
|
|
|
|
|
ret = AVERROR_EXTERNAL; |
|
|
|
|
|
goto fail; |
|
|
|
|
|
} |
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
fail: |
|
|
|
|
|
ff_pulse_audio_disconnect_context(pa_ml, pa_ctx); |
|
|
|
|
|
return ret; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void pulse_add_detected_device(PulseAudioDeviceList *info, |
|
|
static void pulse_add_detected_device(PulseAudioDeviceList *info, |
|
|
const char *name, const char *description) |
|
|
const char *name, const char *description) |
|
|
{ |
|
|
{ |
|
|
@@ -138,11 +197,9 @@ static void pulse_server_info_cb(pa_context *c, const pa_server_info *i, void *u |
|
|
int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, int output) |
|
|
int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, int output) |
|
|
{ |
|
|
{ |
|
|
pa_mainloop *pa_ml = NULL; |
|
|
pa_mainloop *pa_ml = NULL; |
|
|
pa_mainloop_api *pa_mlapi = NULL; |
|
|
|
|
|
pa_operation *pa_op = NULL; |
|
|
pa_operation *pa_op = NULL; |
|
|
pa_context *pa_ctx = NULL; |
|
|
pa_context *pa_ctx = NULL; |
|
|
enum pa_operation_state op_state; |
|
|
enum pa_operation_state op_state; |
|
|
enum PulseAudioContextState loop_state = PULSE_CONTEXT_INITIALIZING; |
|
|
|
|
|
PulseAudioDeviceList dev_list = { 0 }; |
|
|
PulseAudioDeviceList dev_list = { 0 }; |
|
|
int i; |
|
|
int i; |
|
|
|
|
|
|
|
|
@@ -152,28 +209,9 @@ int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, in |
|
|
return AVERROR(EINVAL); |
|
|
return AVERROR(EINVAL); |
|
|
devices->nb_devices = 0; |
|
|
devices->nb_devices = 0; |
|
|
devices->devices = NULL; |
|
|
devices->devices = NULL; |
|
|
if (!(pa_ml = pa_mainloop_new())) |
|
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
if (!(pa_mlapi = pa_mainloop_get_api(pa_ml))) { |
|
|
|
|
|
dev_list.error_code = AVERROR_EXTERNAL; |
|
|
|
|
|
goto fail; |
|
|
|
|
|
} |
|
|
|
|
|
if (!(pa_ctx = pa_context_new(pa_mlapi, "Query devices"))) { |
|
|
|
|
|
dev_list.error_code = AVERROR(ENOMEM); |
|
|
|
|
|
goto fail; |
|
|
|
|
|
} |
|
|
|
|
|
pa_context_set_state_callback(pa_ctx, pa_state_cb, &loop_state); |
|
|
|
|
|
if (pa_context_connect(pa_ctx, server, 0, NULL) < 0) { |
|
|
|
|
|
dev_list.error_code = AVERROR_EXTERNAL; |
|
|
|
|
|
goto fail; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while (loop_state == PULSE_CONTEXT_INITIALIZING) |
|
|
|
|
|
pa_mainloop_iterate(pa_ml, 1, NULL); |
|
|
|
|
|
if (loop_state == PULSE_CONTEXT_FINISHED) { |
|
|
|
|
|
dev_list.error_code = AVERROR_EXTERNAL; |
|
|
|
|
|
|
|
|
if ((dev_list.error_code = ff_pulse_audio_connect_context(&pa_ml, &pa_ctx, server, "Query devices")) < 0) |
|
|
goto fail; |
|
|
goto fail; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (output) |
|
|
if (output) |
|
|
pa_op = pa_context_get_sink_info_list(pa_ctx, pulse_audio_sink_device_cb, &dev_list); |
|
|
pa_op = pa_context_get_sink_info_list(pa_ctx, pulse_audio_sink_device_cb, &dev_list); |
|
|
@@ -206,11 +244,6 @@ int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, in |
|
|
|
|
|
|
|
|
fail: |
|
|
fail: |
|
|
av_free(dev_list.default_device); |
|
|
av_free(dev_list.default_device); |
|
|
if(pa_ctx) |
|
|
|
|
|
pa_context_disconnect(pa_ctx); |
|
|
|
|
|
if (pa_ctx) |
|
|
|
|
|
pa_context_unref(pa_ctx); |
|
|
|
|
|
if (pa_ml) |
|
|
|
|
|
pa_mainloop_free(pa_ml); |
|
|
|
|
|
|
|
|
ff_pulse_audio_disconnect_context(&pa_ml, &pa_ctx); |
|
|
return dev_list.error_code; |
|
|
return dev_list.error_code; |
|
|
} |
|
|
} |