FFmpeg
pulse_audio_common.c
Go to the documentation of this file.
1 /*
2  * Pulseaudio common
3  * Copyright (c) 2014 Lukasz Marek
4  * Copyright (c) 2011 Luca Barbato <lu_zero@gentoo.org>
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 #include "pulse_audio_common.h"
24 #include "libavutil/attributes.h"
25 #include "libavutil/avstring.h"
26 #include "libavutil/mem.h"
27 #include "libavutil/avassert.h"
28 
30 {
31  switch (codec_id) {
32  case AV_CODEC_ID_PCM_U8: return PA_SAMPLE_U8;
33  case AV_CODEC_ID_PCM_ALAW: return PA_SAMPLE_ALAW;
34  case AV_CODEC_ID_PCM_MULAW: return PA_SAMPLE_ULAW;
35  case AV_CODEC_ID_PCM_S16LE: return PA_SAMPLE_S16LE;
36  case AV_CODEC_ID_PCM_S16BE: return PA_SAMPLE_S16BE;
37  case AV_CODEC_ID_PCM_F32LE: return PA_SAMPLE_FLOAT32LE;
38  case AV_CODEC_ID_PCM_F32BE: return PA_SAMPLE_FLOAT32BE;
39  case AV_CODEC_ID_PCM_S32LE: return PA_SAMPLE_S32LE;
40  case AV_CODEC_ID_PCM_S32BE: return PA_SAMPLE_S32BE;
41  case AV_CODEC_ID_PCM_S24LE: return PA_SAMPLE_S24LE;
42  case AV_CODEC_ID_PCM_S24BE: return PA_SAMPLE_S24BE;
43  default: return PA_SAMPLE_INVALID;
44  }
45 }
46 
51 };
52 
53 typedef struct PulseAudioDeviceList {
56  int output;
59 
60 static void pa_state_cb(pa_context *c, void *userdata)
61 {
62  enum PulseAudioContextState *context_state = userdata;
63 
64  switch (pa_context_get_state(c)) {
65  case PA_CONTEXT_FAILED:
66  case PA_CONTEXT_TERMINATED:
67  *context_state = PULSE_CONTEXT_FINISHED;
68  break;
69  case PA_CONTEXT_READY:
70  *context_state = PULSE_CONTEXT_READY;
71  break;
72  default:
73  break;
74  }
75 }
76 
77 void ff_pulse_audio_disconnect_context(pa_mainloop **pa_ml, pa_context **pa_ctx)
78 {
79  av_assert0(pa_ml);
80  av_assert0(pa_ctx);
81 
82  if (*pa_ctx) {
83  pa_context_set_state_callback(*pa_ctx, NULL, NULL);
84  pa_context_disconnect(*pa_ctx);
85  pa_context_unref(*pa_ctx);
86  }
87  if (*pa_ml)
88  pa_mainloop_free(*pa_ml);
89  *pa_ml = NULL;
90  *pa_ctx = NULL;
91 }
92 
93 int ff_pulse_audio_connect_context(pa_mainloop **pa_ml, pa_context **pa_ctx,
94  const char *server, const char *description)
95 {
96  int ret;
97  pa_mainloop_api *pa_mlapi = NULL;
99 
100  av_assert0(pa_ml);
101  av_assert0(pa_ctx);
102 
103  *pa_ml = NULL;
104  *pa_ctx = NULL;
105 
106  if (!(*pa_ml = pa_mainloop_new()))
107  return AVERROR(ENOMEM);
108  if (!(pa_mlapi = pa_mainloop_get_api(*pa_ml))) {
109  ret = AVERROR_EXTERNAL;
110  goto fail;
111  }
112  if (!(*pa_ctx = pa_context_new(pa_mlapi, description))) {
113  ret = AVERROR(ENOMEM);
114  goto fail;
115  }
116  pa_context_set_state_callback(*pa_ctx, pa_state_cb, &context_state);
117  if (pa_context_connect(*pa_ctx, server, 0, NULL) < 0) {
118  ret = AVERROR_EXTERNAL;
119  goto fail;
120  }
121 
122  while (context_state == PULSE_CONTEXT_INITIALIZING)
123  pa_mainloop_iterate(*pa_ml, 1, NULL);
124  if (context_state == PULSE_CONTEXT_FINISHED) {
125  ret = AVERROR_EXTERNAL;
126  goto fail;
127  }
128  return 0;
129 
130  fail:
131  ff_pulse_audio_disconnect_context(pa_ml, pa_ctx);
132  return ret;
133 }
134 
136  const char *name, const char *description)
137 {
138  int ret;
139  AVDeviceInfo *new_device = NULL;
140 
141  if (info->error_code)
142  return;
143 
144  new_device = av_mallocz(sizeof(AVDeviceInfo));
145  if (!new_device) {
146  info->error_code = AVERROR(ENOMEM);
147  return;
148  }
149 
150  new_device->device_description = av_strdup(description);
151  new_device->device_name = av_strdup(name);
152 
153  if (!new_device->device_description || !new_device->device_name) {
154  info->error_code = AVERROR(ENOMEM);
155  goto fail;
156  }
157 
158  if ((ret = av_dynarray_add_nofree(&info->devices->devices,
159  &info->devices->nb_devices, new_device)) < 0) {
160  info->error_code = ret;
161  goto fail;
162  }
163  return;
164 
165  fail:
166  av_freep(&new_device->device_description);
167  av_freep(&new_device->device_name);
168  av_free(new_device);
169 
170 }
171 
172 static void pulse_audio_source_device_cb(pa_context *c, const pa_source_info *dev,
173  int eol, void *userdata)
174 {
175  if (!eol)
176  pulse_add_detected_device(userdata, dev->name, dev->description);
177 }
178 
179 static void pulse_audio_sink_device_cb(pa_context *c, const pa_sink_info *dev,
180  int eol, void *userdata)
181 {
182  if (!eol)
183  pulse_add_detected_device(userdata, dev->name, dev->description);
184 }
185 
186 static void pulse_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata)
187 {
188  PulseAudioDeviceList *info = userdata;
189  if (info->output)
190  info->default_device = av_strdup(i->default_sink_name);
191  else
192  info->default_device = av_strdup(i->default_source_name);
193  if (!info->default_device)
194  info->error_code = AVERROR(ENOMEM);
195 }
196 
198 {
199  pa_mainloop *pa_ml = NULL;
200  pa_operation *pa_op = NULL;
201  pa_context *pa_ctx = NULL;
202  enum pa_operation_state op_state;
203  PulseAudioDeviceList dev_list = { 0 };
204  int i;
205 
206  dev_list.output = output;
207  dev_list.devices = devices;
208  if (!devices)
209  return AVERROR(EINVAL);
210  devices->nb_devices = 0;
211  devices->devices = NULL;
212 
213  if ((dev_list.error_code = ff_pulse_audio_connect_context(&pa_ml, &pa_ctx, server, "Query devices")) < 0)
214  goto fail;
215 
216  if (output)
217  pa_op = pa_context_get_sink_info_list(pa_ctx, pulse_audio_sink_device_cb, &dev_list);
218  else
219  pa_op = pa_context_get_source_info_list(pa_ctx, pulse_audio_source_device_cb, &dev_list);
220  while ((op_state = pa_operation_get_state(pa_op)) == PA_OPERATION_RUNNING)
221  pa_mainloop_iterate(pa_ml, 1, NULL);
222  if (op_state != PA_OPERATION_DONE)
223  dev_list.error_code = AVERROR_EXTERNAL;
224  pa_operation_unref(pa_op);
225  if (dev_list.error_code < 0)
226  goto fail;
227 
228  pa_op = pa_context_get_server_info(pa_ctx, pulse_server_info_cb, &dev_list);
229  while ((op_state = pa_operation_get_state(pa_op)) == PA_OPERATION_RUNNING)
230  pa_mainloop_iterate(pa_ml, 1, NULL);
231  if (op_state != PA_OPERATION_DONE)
232  dev_list.error_code = AVERROR_EXTERNAL;
233  pa_operation_unref(pa_op);
234  if (dev_list.error_code < 0)
235  goto fail;
236 
237  devices->default_device = -1;
238  for (i = 0; i < devices->nb_devices; i++) {
239  if (!strcmp(devices->devices[i]->device_name, dev_list.default_device)) {
240  devices->default_device = i;
241  break;
242  }
243  }
244 
245  fail:
246  av_free(dev_list.default_device);
247  ff_pulse_audio_disconnect_context(&pa_ml, &pa_ctx);
248  return dev_list.error_code;
249 }
#define NULL
Definition: coverity.c:32
Structure describes basic parameters of the device.
Definition: avdevice.h:452
PulseAudioContextState
char * device_description
human friendly name
Definition: avdevice.h:454
Memory handling functions.
enum AVCodecID codec_id
Definition: qsv.c:77
char * device_name
device name, format depends on device
Definition: avdevice.h:453
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
Macro definitions for various function/variable attributes.
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
#define av_cold
Definition: attributes.h:82
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
int ff_pulse_audio_connect_context(pa_mainloop **pa_ml, pa_context **pa_ctx, const char *server, const char *description)
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
Definition: mem.c:294
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: avcodec.h:215
Tag description
Definition: snow.txt:206
simple assert() macros that are a bit more flexible than ISO C assert().
AVDeviceInfo ** devices
list of autodetected devices
Definition: avdevice.h:461
#define fail()
Definition: checkasm.h:122
MIPS optimizations info
Definition: mips.txt:2
void ff_pulse_audio_disconnect_context(pa_mainloop **pa_ml, pa_context **pa_ctx)
pa_sample_format_t av_cold ff_codec_id_to_pulse_format(enum AVCodecID codec_id)
static void pa_state_cb(pa_context *c, void *userdata)
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:251
static void pulse_audio_sink_device_cb(pa_context *c, const pa_sink_info *dev, int eol, void *userdata)
static void pulse_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata)
int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, int output)
int default_device
index of default device or -1 if no default
Definition: avdevice.h:463
List of devices.
Definition: avdevice.h:460
static void pulse_audio_source_device_cb(pa_context *c, const pa_source_info *dev, int eol, void *userdata)
#define av_free(p)
AVDeviceInfoList * devices
#define av_freep(p)
static void pulse_add_detected_device(PulseAudioDeviceList *info, const char *name, const char *description)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
int nb_devices
number of autodetected devices
Definition: avdevice.h:462
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
const char * name
Definition: opengl_enc.c:102