1/*
2 * libjingle
3 * Copyright 2004--2010, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef TALK_SOUND_PULSEAUDIOSOUNDSYSTEM_H_
29#define TALK_SOUND_PULSEAUDIOSOUNDSYSTEM_H_
30
31#ifdef HAVE_LIBPULSE
32
33#include "talk/base/constructormagic.h"
34#include "talk/sound/pulseaudiosymboltable.h"
35#include "talk/sound/soundsysteminterface.h"
36
37namespace cricket {
38
39class PulseAudioInputStream;
40class PulseAudioOutputStream;
41class PulseAudioStream;
42
43// Sound system implementation for PulseAudio, a cross-platform sound server
44// (but commonly used only on Linux, which is the only platform we support
45// it on).
46// Init(), Terminate(), and the destructor should never be invoked concurrently,
47// but all other methods are thread-safe.
48class PulseAudioSoundSystem : public SoundSystemInterface {
49  friend class PulseAudioInputStream;
50  friend class PulseAudioOutputStream;
51  friend class PulseAudioStream;
52 public:
53  static SoundSystemInterface *Create() {
54    return new PulseAudioSoundSystem();
55  }
56
57  PulseAudioSoundSystem();
58
59  virtual ~PulseAudioSoundSystem();
60
61  virtual bool Init();
62  virtual void Terminate();
63
64  virtual bool EnumeratePlaybackDevices(SoundDeviceLocatorList *devices);
65  virtual bool EnumerateCaptureDevices(SoundDeviceLocatorList *devices);
66
67  virtual bool GetDefaultPlaybackDevice(SoundDeviceLocator **device);
68  virtual bool GetDefaultCaptureDevice(SoundDeviceLocator **device);
69
70  virtual SoundOutputStreamInterface *OpenPlaybackDevice(
71      const SoundDeviceLocator *device,
72      const OpenParams &params);
73  virtual SoundInputStreamInterface *OpenCaptureDevice(
74      const SoundDeviceLocator *device,
75      const OpenParams &params);
76
77  virtual const char *GetName() const;
78
79 private:
80  bool IsInitialized();
81
82  static void ConnectToPulseCallbackThunk(pa_context *context, void *userdata);
83
84  void OnConnectToPulseCallback(pa_context *context, bool *connect_done);
85
86  bool ConnectToPulse(pa_context *context);
87
88  pa_context *CreateNewConnection();
89
90  template <typename InfoStruct>
91  bool EnumerateDevices(SoundDeviceLocatorList *devices,
92                        pa_operation *(*enumerate_fn)(
93                            pa_context *c,
94                            void (*callback_fn)(
95                                pa_context *c,
96                                const InfoStruct *i,
97                                int eol,
98                                void *userdata),
99                            void *userdata),
100                        void (*callback_fn)(
101                            pa_context *c,
102                            const InfoStruct *i,
103                            int eol,
104                            void *userdata));
105
106  static void EnumeratePlaybackDevicesCallbackThunk(pa_context *unused,
107                                                    const pa_sink_info *info,
108                                                    int eol,
109                                                    void *userdata);
110
111  static void EnumerateCaptureDevicesCallbackThunk(pa_context *unused,
112                                                   const pa_source_info *info,
113                                                   int eol,
114                                                   void *userdata);
115
116  void OnEnumeratePlaybackDevicesCallback(
117      SoundDeviceLocatorList *devices,
118      const pa_sink_info *info,
119      int eol);
120
121  void OnEnumerateCaptureDevicesCallback(
122      SoundDeviceLocatorList *devices,
123      const pa_source_info *info,
124      int eol);
125
126  template <const char *(pa_server_info::*field)>
127  static void GetDefaultDeviceCallbackThunk(
128      pa_context *unused,
129      const pa_server_info *info,
130      void *userdata);
131
132  template <const char *(pa_server_info::*field)>
133  void OnGetDefaultDeviceCallback(
134      const pa_server_info *info,
135      SoundDeviceLocator **device);
136
137  template <const char *(pa_server_info::*field)>
138  bool GetDefaultDevice(SoundDeviceLocator **device);
139
140  static void StreamStateChangedCallbackThunk(pa_stream *stream,
141                                              void *userdata);
142
143  void OnStreamStateChangedCallback(pa_stream *stream);
144
145  template <typename StreamInterface>
146  StreamInterface *OpenDevice(
147      const SoundDeviceLocator *device,
148      const OpenParams &params,
149      const char *stream_name,
150      StreamInterface *(PulseAudioSoundSystem::*connect_fn)(
151          pa_stream *stream,
152          const char *dev,
153          int flags,
154          pa_stream_flags_t pa_flags,
155          int latency,
156          const pa_sample_spec &spec));
157
158  SoundOutputStreamInterface *ConnectOutputStream(
159      pa_stream *stream,
160      const char *dev,
161      int flags,
162      pa_stream_flags_t pa_flags,
163      int latency,
164      const pa_sample_spec &spec);
165
166  SoundInputStreamInterface *ConnectInputStream(
167      pa_stream *stream,
168      const char *dev,
169      int flags,
170      pa_stream_flags_t pa_flags,
171      int latency,
172      const pa_sample_spec &spec);
173
174  bool FinishOperation(pa_operation *op);
175
176  void Lock();
177  void Unlock();
178  void Wait();
179  void Signal();
180
181  const char *LastError();
182
183  pa_threaded_mainloop *mainloop_;
184  pa_context *context_;
185  PulseAudioSymbolTable symbol_table_;
186
187  DISALLOW_COPY_AND_ASSIGN(PulseAudioSoundSystem);
188};
189
190}  // namespace cricket
191
192#endif  // HAVE_LIBPULSE
193
194#endif  // TALK_SOUND_PULSEAUDIOSOUNDSYSTEM_H_
195