PortAudio  2.0
pa_linux_pulseaudio_internal.h
Go to the documentation of this file.
1 
2 /*
3  * PulseAudio host to play natively in Linux based systems without
4  * ALSA emulation
5  *
6  * Copyright (c) 2014-2023 Tuukka Pasanen <tuukka.pasanen@ilmi.fi>
7  * Copyright (c) 2016 Sqweek
8  *
9  * Based on the Open Source API proposed by Ross Bencina
10  * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining
13  * a copy of this software and associated documentation files
14  * (the "Software"), to deal in the Software without restriction,
15  * including without limitation the rights to use, copy, modify, merge,
16  * publish, distribute, sublicense, and/or sell copies of the Software,
17  * and to permit persons to whom the Software is furnished to do so,
18  * subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be
21  * included in all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
27  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
28  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30  */
31 
32 /*
33  * The text above constitutes the entire PortAudio license; however,
34  * the PortAudio community also makes the following non-binding requests:
35  *
36  * Any person wishing to distribute modifications to the Software is
37  * requested to send the modifications to the original developer so that
38  * they can be incorporated into the canonical version. It is also
39  * requested that these non-binding requests be included along with the
40  * license above.
41  */
42 
43 #ifndef _PA_HOSTAPI_PULSEAUDIO_H_
44 #define _PA_HOSTAPI_PULSEAUDIO_H_
45 
46 #include "pa_util.h"
47 #include "pa_allocation.h"
48 #include "pa_hostapi.h"
49 #include "pa_stream.h"
50 #include "pa_cpuload.h"
51 #include "pa_process.h"
52 
53 #include "pa_unix_util.h"
54 #include "pa_ringbuffer.h"
55 #include "pa_debugprint.h"
56 
57 /* PulseAudio headers */
58 #include <stdio.h>
59 #include <string.h>
60 #include <pulse/pulseaudio.h>
61 
62 #ifdef __cplusplus
63 extern "C"
64 {
65 #endif /* __cplusplus */
66 
67 /* prototypes for functions declared in this file */
68 
69 #define PA_PULSEAUDIO_SET_LAST_HOST_ERROR(errorCode, errorText) \
70  PaUtil_SetLastHostErrorInfo(paInDevelopment, errorCode, errorText)
71 
72 #define PAPULSEAUDIO_MAX_DEVICECOUNT 1024
73 #define PAPULSEAUDIO_MAX_DEVICENAME 1024
74 
75 /* Default latency values to expose. Chosen by trial and error to be reasonable. */
76 #define PA_PULSEAUDIO_DEFAULT_MIN_LATENCY 0.010
77 #define PA_PULSEAUDIO_DEFAULT_MAX_LATENCY 0.080
78 
79 /* Just some value that Pulseaudio can handle */
80 #define PAPULSEAUDIO_FRAMESPERBUFFERUNSPEC 32
81 
82 /* Assuming of 2 seconds of 44100 Hz sample rate with FLOAT (4 bytes) and stereo channels (2 channels).
83  You should have pretty good size buffer with this. If output/intput doesn't happens in 2 second we
84  have more trouble than this buffer.
85  @todo change this to something more sophisticated */
86 #define PULSEAUDIO_BUFFER_SIZE (96100 * 4 * 2)
87 
88 typedef struct
89 {
93 
95 
98  char *pulseaudioDeviceNames[PAPULSEAUDIO_MAX_DEVICECOUNT];
100 
101  /* PulseAudio stuff goes here */
102  pa_threaded_mainloop *mainloop;
103  pa_mainloop_api *mainloopApi;
104  pa_context *context;
106  pa_time_event *timeEvent;
107 }
109 
110 /* PaPulseAudio_Stream - a stream data structure specifically for this implementation */
111 
112 typedef struct PaPulseAudio_Stream
113 {
118 
119  unsigned long framesPerHostCallback;
120  pa_threaded_mainloop *mainloop;
121  pa_context *context;
122  pa_sample_spec outputSampleSpec;
123  pa_sample_spec inputSampleSpec;
124  pa_stream *outputStream;
125  pa_stream *inputStream;
126  pa_buffer_attr outputBufferAttr;
127  pa_buffer_attr inputBufferAttr;
128  unsigned int suggestedLatencyUSecs;
132 
137 
140 
143 
145 
146  size_t missedBytes;
147 
148  /* Used in communication between threads
149  *
150  * State machine works like this:
151  * When stream is wanted to start with Pa_StartStream
152  * then isActive is 1 if opening of devices goes well
153  * and isStopped is then 0.
154  *
155  * When requested to stop isStopped is 1 on isActive is 0
156  * and nothing should be written to ouput or read from input
157  * anymore
158  *
159  * Pulseaudio does not like this as it creates streams and they
160  * start when they are ready and it can be after we have
161  * exited Pa_StartStream or before if get's kicked up very fast
162  *
163  * pulseaudioIsActive and pulseaudioIsStopped are used to find if
164  * there is stream active or stopped in pulseaudio side. They
165  * live their own life besides isActive and isStopped to make sure
166  * that portaudio will have input and output available before
167  * reading or writing to stream.
168  */
169  volatile sig_atomic_t isActive;
170  volatile sig_atomic_t isStopped;
171  volatile sig_atomic_t pulseaudioIsActive;
172  volatile sig_atomic_t pulseaudioIsStopped;
173 
174 }
176 
177 /* PulseAudio Error checking macro */
178 #define PA_PULSEAUDIO_IS_ERROR(pastream, errorCode) \
179  if( !(pastream) || \
180  !(pastream)->context || \
181  !PA_CONTEXT_IS_GOOD( pa_context_get_state( (pastream)->context ) ) || \
182  ( (pastream)->outputStream && \
183  !PA_STREAM_IS_GOOD( pa_stream_get_state( (pastream)->outputStream ) ) ) || \
184  ( (pastream)->inputStream && \
185  !PA_STREAM_IS_GOOD( pa_stream_get_state( (pastream)->inputStream ) ) ) ) \
186  { \
187  if( !(pastream) || \
188  ( (pastream)->context && \
189  pa_context_get_state( (pastream)->context ) == PA_CONTEXT_FAILED ) || \
190  ( (pastream)->outputStream && \
191  pa_stream_get_state( (pastream)->outputStream ) == PA_STREAM_FAILED ) || \
192  ( (pastream)->inputStream && \
193  pa_stream_get_state( (pastream)->inputStream ) == PA_STREAM_FAILED ) ) \
194  { \
195  return errorCode; \
196  } \
197  } \
198  if( !pastream->isActive || pastream->isStopped ) \
199  { \
200  return paStreamIsStopped; \
201  }
202 
203 void PaPulseAudio_Lock( pa_threaded_mainloop *mainloop );
204 
205 void PaPulseAudio_UnLock( pa_threaded_mainloop *mainloop );
206 
208  PaHostApiIndex index );
209 
210 void Terminate( struct PaUtilHostApiRepresentation *hostApi );
211 
212 
214  const PaStreamParameters * inputParameters,
215  const PaStreamParameters * outputParameters,
216  double sampleRate );
217 
219  PaStream ** s,
220  const PaStreamParameters * inputParameters,
221  const PaStreamParameters * outputParameters,
222  double sampleRate,
223  unsigned long framesPerBuffer,
224  PaStreamFlags streamFlags,
225  PaStreamCallback * streamCallback,
226  void *userData );
227 
228 
230 PaError IsStreamActive( PaStream * stream );
231 
232 PaTime GetStreamTime( PaStream * stream );
233 double GetStreamCpuLoad( PaStream * stream );
234 
237 
239 
240 void PaPulseAudio_CheckContextStateCb( pa_context * c,
241  void *userdata );
242 void PaPulseAudio_ServerInfoCb( pa_context *c,
243  const pa_server_info *i,
244  void *userdata );
245 
246 void PaPulseAudio_SinkListCb( pa_context * c,
247  const pa_sink_info * l,
248  int eol,
249  void *userdata );
250 
251 void PaPulseAudio_SourceListCb( pa_context * c,
252  const pa_source_info * l,
253  int eol,
254  void *userdata );
255 
256 void PaPulseAudio_StreamStateCb( pa_stream * s,
257  void *userdata );
258 
259 void PaPulseAudio_StreamStartedCb( pa_stream * s,
260  void *userdata );
261 
262 void PaPulseAudio_StreamUnderflowCb( pa_stream * s,
263  void *userdata );
264 
266  pa_sample_spec * pulseaudiosf
267 );
268 
269 #ifdef __cplusplus
270 }
271 #endif /* __cplusplus */
272 
273 
274 #endif
PaUtilStreamRepresentation streamRepresentation
Definition: pa_linux_pulseaudio_internal.h:114
pa_buffer_attr inputBufferAttr
Definition: pa_linux_pulseaudio_internal.h:127
void Terminate(struct PaUtilHostApiRepresentation *hostApi)
Definition: pa_linux_pulseaudio.c:802
struct PaPulseAudio_Stream PaPulseAudio_Stream
Single-reader single-writer lock-free ring buffer.
pa_buffer_attr outputBufferAttr
Definition: pa_linux_pulseaudio_internal.h:126
int PaHostApiIndex
Definition: portaudio.h:239
Definition: pa_cpuload.h:56
PaUtilStreamInterface callbackStreamInterface
Definition: pa_linux_pulseaudio_internal.h:91
pa_threaded_mainloop * mainloop
Definition: pa_linux_pulseaudio_internal.h:102
PaUtilRingBuffer inputRing
Definition: pa_linux_pulseaudio_internal.h:144
void PaStream
Definition: portaudio.h:639
Definition: pa_ringbuffer.h:93
double GetStreamCpuLoad(PaStream *s)
Definition: pa_linux_pulseaudio.c:1421
Definition: portaudio.h:504
volatile sig_atomic_t isActive
Definition: pa_linux_pulseaudio_internal.h:169
pa_time_event * timeEvent
Definition: pa_linux_pulseaudio_internal.h:106
int outputChannelCount
Definition: pa_linux_pulseaudio_internal.h:130
Definition: pa_linux_pulseaudio_internal.h:112
void PaPulseAudio_Lock(pa_threaded_mainloop *mainloop)
Definition: pa_linux_pulseaudio_cb.c:110
volatile sig_atomic_t pulseaudioIsStopped
Definition: pa_linux_pulseaudio_internal.h:172
void PaPulseAudio_StreamStateCb(pa_stream *s, void *userdata)
Definition: pa_linux_pulseaudio.c:472
PaDeviceIndex outputDevice
Definition: pa_linux_pulseaudio_internal.h:139
PaError IsFormatSupported(struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate)
Definition: pa_linux_pulseaudio.c:815
int PaStreamCallback(const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
Definition: portaudio.h:834
size_t maxFramesPerBuffer
Definition: pa_linux_pulseaudio_internal.h:133
int PaPulseAudio_CheckConnection(PaPulseAudio_HostApiRepresentation *ptr)
Definition: pa_linux_pulseaudio.c:68
PaPulseAudio_HostApiRepresentation * PaPulseAudio_New(void)
Definition: pa_linux_pulseaudio.c:142
pa_sample_spec inputSampleSpec
Definition: pa_linux_pulseaudio_internal.h:123
PaError OpenStream(struct PaUtilHostApiRepresentation *hostApi, PaStream **s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData)
Definition: pa_linux_pulseaudio.c:995
PaUtilAllocationGroup * allocations
Definition: pa_linux_pulseaudio_internal.h:94
void PaPulseAudio_StreamUnderflowCb(pa_stream *s, void *userdata)
Definition: pa_linux_pulseaudio.c:536
void PaPulseAudio_StreamStartedCb(pa_stream *stream, void *userdata)
Definition: pa_linux_pulseaudio_cb.c:453
pa_threaded_mainloop * mainloop
Definition: pa_linux_pulseaudio_internal.h:120
char * inputStreamName
Definition: pa_linux_pulseaudio_internal.h:142
int PaDeviceIndex
Definition: portaudio.h:213
Buffer Processor prototypes. A Buffer Processor performs buffer length adaption, coordinates sample f...
int deviceCount
Definition: pa_linux_pulseaudio_internal.h:105
Definition: pa_stream.h:67
pa_context * context
Definition: pa_linux_pulseaudio_internal.h:121
Allocation Group prototypes. An Allocation Group makes it easy to allocate multiple blocks of memory ...
Interfaces and representation structures used by pa_front.c to manage and communicate with host API i...
unsigned int suggestedLatencyUSecs
Definition: pa_linux_pulseaudio_internal.h:128
PaError IsStreamActive(PaStream *s)
Definition: pa_linux_pulseaudio.c:1381
unsigned long framesPerHostCallback
Definition: pa_linux_pulseaudio_internal.h:119
void PaPulseAudio_CheckContextStateCb(pa_context *c, void *userdata)
Definition: pa_linux_pulseaudio.c:258
Stream interfaces, representation structures and helper functions used to interface between pa_front...
pa_context * context
Definition: pa_linux_pulseaudio_internal.h:104
void PaPulseAudio_UnLock(pa_threaded_mainloop *mainloop)
Definition: pa_linux_pulseaudio_cb.c:118
Definition: pa_allocation.h:65
void PaPulseAudio_SinkListCb(pa_context *c, const pa_sink_info *l, int eol, void *userdata)
Definition: pa_linux_pulseaudio.c:368
unsigned long PaStreamFlags
Definition: portaudio.h:657
int PaError
Definition: portaudio.h:121
Definition: pa_stream.h:147
pa_sample_spec pulseaudioDefaultSampleSpec
Definition: pa_linux_pulseaudio_internal.h:99
PaUtilHostApiRepresentation inheritedHostApiRep
Definition: pa_linux_pulseaudio_internal.h:90
int inputChannelCount
Definition: pa_linux_pulseaudio_internal.h:131
Definition: portaudio.h:542
pa_stream * outputStream
Definition: pa_linux_pulseaudio_internal.h:124
volatile sig_atomic_t pulseaudioIsActive
Definition: pa_linux_pulseaudio_internal.h:171
int outputUnderflows
Definition: pa_linux_pulseaudio_internal.h:129
PaUtilBufferProcessor bufferProcessor
Definition: pa_linux_pulseaudio_internal.h:116
unsigned long PaSampleFormat
Definition: portaudio.h:488
PaPulseAudio_HostApiRepresentation * hostapi
Definition: pa_linux_pulseaudio_internal.h:117
PaError PaPulseAudio_Initialize(PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex)
Definition: pa_linux_pulseaudio.c:562
void PaPulseAudio_Free(PaPulseAudio_HostApiRepresentation *ptr)
Definition: pa_linux_pulseaudio.c:207
volatile sig_atomic_t isStopped
Definition: pa_linux_pulseaudio_internal.h:170
pa_mainloop_api * mainloopApi
Definition: pa_linux_pulseaudio_internal.h:103
Prototypes for utility functions used by PortAudio implementations.
PaUtilCpuLoadMeasurer cpuLoadMeasurer
Definition: pa_linux_pulseaudio_internal.h:115
size_t maxFramesHostPerBuffer
Definition: pa_linux_pulseaudio_internal.h:134
PaHostApiIndex hostApiIndex
Definition: pa_linux_pulseaudio_internal.h:96
pa_sample_spec outputSampleSpec
Definition: pa_linux_pulseaudio_internal.h:122
int inputFrameSize
Definition: pa_linux_pulseaudio_internal.h:136
The main buffer processor data structure.
Definition: pa_process.h:253
Functions to assist in measuring the CPU utilization of a callback stream. Used to implement the Pa_G...
double PaTime
Definition: portaudio.h:464
int outputFrameSize
Definition: pa_linux_pulseaudio_internal.h:135
Definition: pa_linux_pulseaudio_internal.h:88
PaError PaPulseAudio_ConvertPortaudioFormatToPaPulseAudio_(PaSampleFormat portaudiosf, pa_sample_spec *pulseaudiosf)
Definition: pa_linux_pulseaudio.c:915
PaError IsStreamStopped(PaStream *s)
Definition: pa_linux_pulseaudio.c:1374
PaDeviceIndex inputDevice
Definition: pa_linux_pulseaudio_internal.h:138
char * outputStreamName
Definition: pa_linux_pulseaudio_internal.h:141
Definition: pa_hostapi.h:201
pa_stream * inputStream
Definition: pa_linux_pulseaudio_internal.h:125
size_t missedBytes
Definition: pa_linux_pulseaudio_internal.h:146
void PaPulseAudio_ServerInfoCb(pa_context *c, const pa_server_info *i, void *userdata)
Definition: pa_linux_pulseaudio.c:276
void PaPulseAudio_SourceListCb(pa_context *c, const pa_source_info *l, int eol, void *userdata)
Definition: pa_linux_pulseaudio.c:420
#define PAPULSEAUDIO_MAX_DEVICECOUNT
Definition: pa_linux_pulseaudio_internal.h:72
PaUtilStreamInterface blockingStreamInterface
Definition: pa_linux_pulseaudio_internal.h:92
PaTime GetStreamTime(PaStream *s)
Definition: pa_linux_pulseaudio.c:1388