1/*
2 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#ifndef WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_OPENSLES_OUTPUT_H_
12#define WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_OPENSLES_OUTPUT_H_
13
14#include <SLES/OpenSLES.h>
15#include <SLES/OpenSLES_Android.h>
16#include <SLES/OpenSLES_AndroidConfiguration.h>
17
18#include "webrtc/modules/audio_device/android/audio_manager_jni.h"
19#include "webrtc/modules/audio_device/android/low_latency_event.h"
20#include "webrtc/modules/audio_device/android/audio_common.h"
21#include "webrtc/modules/audio_device/include/audio_device_defines.h"
22#include "webrtc/modules/audio_device/include/audio_device.h"
23#include "webrtc/system_wrappers/interface/scoped_ptr.h"
24
25namespace webrtc {
26
27class AudioDeviceBuffer;
28class CriticalSectionWrapper;
29class FineAudioBuffer;
30class SingleRwFifo;
31class ThreadWrapper;
32
33// OpenSL implementation that facilitate playing PCM data to an android device.
34// This class is Thread-compatible. I.e. Given an instance of this class, calls
35// to non-const methods require exclusive access to the object.
36class OpenSlesOutput : public PlayoutDelayProvider {
37 public:
38  explicit OpenSlesOutput(const int32_t id);
39  virtual ~OpenSlesOutput();
40
41  static int32_t SetAndroidAudioDeviceObjects(void* javaVM,
42                                              void* env,
43                                              void* context);
44  static void ClearAndroidAudioDeviceObjects();
45
46  // Main initializaton and termination
47  int32_t Init();
48  int32_t Terminate();
49  bool Initialized() const { return initialized_; }
50
51  // Device enumeration
52  int16_t PlayoutDevices() { return 1; }
53
54  int32_t PlayoutDeviceName(uint16_t index,
55                            char name[kAdmMaxDeviceNameSize],
56                            char guid[kAdmMaxGuidSize]);
57
58  // Device selection
59  int32_t SetPlayoutDevice(uint16_t index);
60  int32_t SetPlayoutDevice(
61      AudioDeviceModule::WindowsDeviceType device) { return 0; }
62
63  // No-op
64  int32_t SetPlayoutSampleRate(uint32_t sample_rate_hz) { return 0; }
65
66  // Audio transport initialization
67  int32_t PlayoutIsAvailable(bool& available);  // NOLINT
68  int32_t InitPlayout();
69  bool PlayoutIsInitialized() const { return play_initialized_; }
70
71  // Audio transport control
72  int32_t StartPlayout();
73  int32_t StopPlayout();
74  bool Playing() const { return playing_; }
75
76  // Audio mixer initialization
77  int32_t InitSpeaker();
78  bool SpeakerIsInitialized() const { return speaker_initialized_; }
79
80  // Speaker volume controls
81  int32_t SpeakerVolumeIsAvailable(bool& available);  // NOLINT
82  int32_t SetSpeakerVolume(uint32_t volume);
83  int32_t SpeakerVolume(uint32_t& volume) const { return 0; }  // NOLINT
84  int32_t MaxSpeakerVolume(uint32_t& maxVolume) const;  // NOLINT
85  int32_t MinSpeakerVolume(uint32_t& minVolume) const;  // NOLINT
86  int32_t SpeakerVolumeStepSize(uint16_t& stepSize) const;  // NOLINT
87
88  // Speaker mute control
89  int32_t SpeakerMuteIsAvailable(bool& available);  // NOLINT
90  int32_t SetSpeakerMute(bool enable) { return -1; }
91  int32_t SpeakerMute(bool& enabled) const { return -1; }  // NOLINT
92
93
94  // Stereo support
95  int32_t StereoPlayoutIsAvailable(bool& available);  // NOLINT
96  int32_t SetStereoPlayout(bool enable);
97  int32_t StereoPlayout(bool& enabled) const;  // NOLINT
98
99  // Delay information and control
100  int32_t SetPlayoutBuffer(const AudioDeviceModule::BufferType type,
101                                   uint16_t sizeMS) { return -1; }
102  int32_t PlayoutBuffer(AudioDeviceModule::BufferType& type,  // NOLINT
103                        uint16_t& sizeMS) const;
104  int32_t PlayoutDelay(uint16_t& delayMS) const;  // NOLINT
105
106
107  // Error and warning information
108  bool PlayoutWarning() const { return false; }
109  bool PlayoutError() const { return false; }
110  void ClearPlayoutWarning() {}
111  void ClearPlayoutError() {}
112
113  // Attach audio buffer
114  void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer);
115
116  // Speaker audio routing
117  int32_t SetLoudspeakerStatus(bool enable);
118  int32_t GetLoudspeakerStatus(bool& enable) const;  // NOLINT
119
120 protected:
121  virtual int PlayoutDelayMs();
122
123 private:
124  enum {
125    kNumInterfaces = 3,
126    // TODO(xians): Reduce the numbers of buffers to improve the latency.
127    //              Currently 30ms worth of buffers are needed due to audio
128    //              pipeline processing jitter. Note: kNumOpenSlBuffers must
129    //              not be changed.
130    // According to the opensles documentation in the ndk:
131    // The lower output latency path is used only if the application requests a
132    // buffer count of 2 or more. Use minimum number of buffers to keep delay
133    // as low as possible.
134    kNumOpenSlBuffers = 2,
135    // NetEq delivers frames on a 10ms basis. This means that every 10ms there
136    // will be a time consuming task. Keeping 10ms worth of buffers will ensure
137    // that there is 10ms to perform the time consuming task without running
138    // into underflow.
139    // In addition to the 10ms that needs to be stored for NetEq processing
140    // there will be jitter in audio pipe line due to the acquisition of locks.
141    // Note: The buffers in the OpenSL queue do not count towards the 10ms of
142    // frames needed since OpenSL needs to have them ready for playout.
143    kNum10MsToBuffer = 6,
144  };
145
146  bool InitSampleRate();
147  bool SetLowLatency();
148  void UpdatePlayoutDelay();
149  // It might be possible to dynamically add or remove buffers based on how
150  // close to depletion the fifo is. Few buffers means low delay. Too few
151  // buffers will cause underrun. Dynamically changing the number of buffer
152  // will greatly increase code complexity.
153  void CalculateNumFifoBuffersNeeded();
154  void AllocateBuffers();
155  int TotalBuffersUsed() const;
156  bool EnqueueAllBuffers();
157  // This function also configures the audio player, e.g. sample rate to use
158  // etc, so it should be called when starting playout.
159  bool CreateAudioPlayer();
160  void DestroyAudioPlayer();
161
162  // When underrun happens there won't be a new frame ready for playout that
163  // can be retrieved yet. Since the OpenSL thread must return ASAP there will
164  // be one less queue available to OpenSL. This function handles this case
165  // gracefully by restarting the audio, pushing silent frames to OpenSL for
166  // playout. This will sound like a click. Underruns are also logged to
167  // make it possible to identify these types of audio artifacts.
168  // This function returns true if there has been underrun. Further processing
169  // of audio data should be avoided until this function returns false again.
170  // The function needs to be protected by |crit_sect_|.
171  bool HandleUnderrun(int event_id, int event_msg);
172
173  static void PlayerSimpleBufferQueueCallback(
174      SLAndroidSimpleBufferQueueItf queueItf,
175      void* pContext);
176  // This function must not take any locks or do any heavy work. It is a
177  // requirement for the OpenSL implementation to work as intended. The reason
178  // for this is that taking locks exposes the OpenSL thread to the risk of
179  // priority inversion.
180  void PlayerSimpleBufferQueueCallbackHandler(
181      SLAndroidSimpleBufferQueueItf queueItf);
182
183  bool StartCbThreads();
184  void StopCbThreads();
185  static bool CbThread(void* context);
186  // This function must be protected against data race with threads calling this
187  // class' public functions. It is a requirement for this class to be
188  // Thread-compatible.
189  bool CbThreadImpl();
190
191  // Java API handle
192  AudioManagerJni audio_manager_;
193
194  int id_;
195  bool initialized_;
196  bool speaker_initialized_;
197  bool play_initialized_;
198
199  // Members that are read/write accessed concurrently by the process thread and
200  // threads calling public functions of this class.
201  scoped_ptr<ThreadWrapper> play_thread_;  // Processing thread
202  scoped_ptr<CriticalSectionWrapper> crit_sect_;
203  // This member controls the starting and stopping of playing audio to the
204  // the device.
205  bool playing_;
206
207  // Only one thread, T1, may push and only one thread, T2, may pull. T1 may or
208  // may not be the same thread as T2. T1 is the process thread and T2 is the
209  // OpenSL thread.
210  scoped_ptr<SingleRwFifo> fifo_;
211  int num_fifo_buffers_needed_;
212  LowLatencyEvent event_;
213  int number_underruns_;
214
215  // OpenSL handles
216  SLObjectItf sles_engine_;
217  SLEngineItf sles_engine_itf_;
218  SLObjectItf sles_player_;
219  SLPlayItf sles_player_itf_;
220  SLAndroidSimpleBufferQueueItf sles_player_sbq_itf_;
221  SLObjectItf sles_output_mixer_;
222
223  // Audio buffers
224  AudioDeviceBuffer* audio_buffer_;
225  scoped_ptr<FineAudioBuffer> fine_buffer_;
226  scoped_ptr<scoped_ptr<int8_t[]>[]> play_buf_;
227  // Index in |rec_buf_| pointing to the audio buffer that will be ready the
228  // next time PlayerSimpleBufferQueueCallbackHandler is invoked.
229  // Ready means buffer is ready to be played out to device.
230  int active_queue_;
231
232  // Audio settings
233  uint32_t speaker_sampling_rate_;
234  int buffer_size_samples_;
235  int buffer_size_bytes_;
236
237  // Audio status
238  uint16_t playout_delay_;
239};
240
241}  // namespace webrtc
242
243#endif  // WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_OPENSLES_OUTPUT_H_
244