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))) {
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) {
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) {
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 
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 
197 int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, int output)
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 }
AV_CODEC_ID_PCM_S16LE
@ AV_CODEC_ID_PCM_S16LE
Definition: codec_id.h:313
AV_CODEC_ID_PCM_F32BE
@ AV_CODEC_ID_PCM_F32BE
Definition: codec_id.h:333
name
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default minimum maximum flags name is the option name
Definition: writing_filters.txt:88
AVERROR
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
PulseAudioDeviceList
Definition: pulse_audio_common.c:53
AVDeviceInfo::device_name
char * device_name
device name, format depends on device
Definition: avdevice.h:458
output
filter_frame For filters that do not use the this method is called when a frame is pushed to the filter s input It can be called at any time except in a reentrant way If the input frame is enough to produce output
Definition: filter_design.txt:225
AVDeviceInfoList::nb_devices
int nb_devices
number of autodetected devices
Definition: avdevice.h:467
pa_state_cb
static void pa_state_cb(pa_context *c, void *userdata)
Definition: pulse_audio_common.c:60
pulse_audio_sink_device_cb
static void pulse_audio_sink_device_cb(pa_context *c, const pa_sink_info *dev, int eol, void *userdata)
Definition: pulse_audio_common.c:179
ff_codec_id_to_pulse_format
pa_sample_format_t av_cold ff_codec_id_to_pulse_format(enum AVCodecID codec_id)
Definition: pulse_audio_common.c:29
PulseAudioDeviceList::output
int output
Definition: pulse_audio_common.c:56
AV_CODEC_ID_PCM_S16BE
@ AV_CODEC_ID_PCM_S16BE
Definition: codec_id.h:314
fail
#define fail()
Definition: checkasm.h:127
pulse_audio_source_device_cb
static void pulse_audio_source_device_cb(pa_context *c, const pa_source_info *dev, int eol, void *userdata)
Definition: pulse_audio_common.c:172
AVDeviceInfoList::devices
AVDeviceInfo ** devices
list of autodetected devices
Definition: avdevice.h:466
avassert.h
description
Tag description
Definition: snow.txt:206
av_cold
#define av_cold
Definition: attributes.h:90
PulseAudioContextState
PulseAudioContextState
Definition: pulse_audio_common.c:47
ff_pulse_audio_get_devices
int ff_pulse_audio_get_devices(AVDeviceInfoList *devices, const char *server, int output)
Definition: pulse_audio_common.c:197
pulse_add_detected_device
static void pulse_add_detected_device(PulseAudioDeviceList *info, const char *name, const char *description)
Definition: pulse_audio_common.c:135
info
MIPS optimizations info
Definition: mips.txt:2
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
AV_CODEC_ID_PCM_MULAW
@ AV_CODEC_ID_PCM_MULAW
Definition: codec_id.h:319
codec_id
enum AVCodecID codec_id
Definition: vaapi_decode.c:369
AV_CODEC_ID_PCM_ALAW
@ AV_CODEC_ID_PCM_ALAW
Definition: codec_id.h:320
NULL
#define NULL
Definition: coverity.c:32
PulseAudioDeviceList::default_device
char * default_device
Definition: pulse_audio_common.c:57
c
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
AVCodecID
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: codec_id.h:47
pulse_audio_common.h
AV_CODEC_ID_PCM_S24LE
@ AV_CODEC_ID_PCM_S24LE
Definition: codec_id.h:325
ff_pulse_audio_disconnect_context
void ff_pulse_audio_disconnect_context(pa_mainloop **pa_ml, pa_context **pa_ctx)
Definition: pulse_audio_common.c:77
AVDeviceInfo
Structure describes basic parameters of the device.
Definition: avdevice.h:457
AVERROR_EXTERNAL
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:59
attributes.h
PULSE_CONTEXT_FINISHED
@ PULSE_CONTEXT_FINISHED
Definition: pulse_audio_common.c:50
AVDeviceInfo::device_description
char * device_description
human friendly name
Definition: avdevice.h:459
PulseAudioDeviceList::error_code
int error_code
Definition: pulse_audio_common.c:55
i
int i
Definition: input.c:406
ff_pulse_audio_connect_context
int ff_pulse_audio_connect_context(pa_mainloop **pa_ml, pa_context **pa_ctx, const char *server, const char *description)
Definition: pulse_audio_common.c:93
PulseAudioDeviceList::devices
AVDeviceInfoList * devices
Definition: pulse_audio_common.c:54
AV_CODEC_ID_PCM_S32BE
@ AV_CODEC_ID_PCM_S32BE
Definition: codec_id.h:322
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:261
ret
ret
Definition: filter_design.txt:187
AVDeviceInfoList
List of devices.
Definition: avdevice.h:465
av_dynarray_add_nofree
int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem)
Add an element to a dynamic array.
Definition: mem.c:320
AVDeviceInfoList::default_device
int default_device
index of default device or -1 if no default
Definition: avdevice.h:468
pulse_server_info_cb
static void pulse_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata)
Definition: pulse_audio_common.c:186
PULSE_CONTEXT_INITIALIZING
@ PULSE_CONTEXT_INITIALIZING
Definition: pulse_audio_common.c:48
av_strdup
char * av_strdup(const char *s)
Duplicate a string.
Definition: mem.c:277
AV_CODEC_ID_PCM_S32LE
@ AV_CODEC_ID_PCM_S32LE
Definition: codec_id.h:321
mem.h
AV_CODEC_ID_PCM_U8
@ AV_CODEC_ID_PCM_U8
Definition: codec_id.h:318
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
av_freep
#define av_freep(p)
Definition: tableprint_vlc.h:35
AV_CODEC_ID_PCM_F32LE
@ AV_CODEC_ID_PCM_F32LE
Definition: codec_id.h:334
avstring.h
PULSE_CONTEXT_READY
@ PULSE_CONTEXT_READY
Definition: pulse_audio_common.c:49
AV_CODEC_ID_PCM_S24BE
@ AV_CODEC_ID_PCM_S24BE
Definition: codec_id.h:326