Beatmup
sles_playback.cpp
Go to the documentation of this file.
1 /*
2  Beatmup image and signal processing library
3  Copyright (C) 2019, lnstadrum
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #ifndef BEATMUP_PROFILE_NOAUDIO
20 
21 #include "sles_playback.h"
22 
23 #include <SLES/OpenSLES.h>
24 #include <SLES/OpenSLES_Android.h>
25 
26 using namespace Beatmup;
27 using namespace Audio;
28 using namespace Android;
29 
30 
31 void playerCallback(SLAndroidSimpleBufferQueueItf queue, void *data);
32 
33 
34 #undef assert
35 
36 inline void assert(SLresult code, const char* message) {
37  if (code != SL_RESULT_SUCCESS)
38  throw Audio::PlaybackException(message, code);
39 }
40 
41 inline void assert(SLresult code, const char* message, const Audio::AbstractPlayback::Mode& mode) {
42  if (code != SL_RESULT_SUCCESS)
43  throw Audio::PlaybackException(message, code, mode);
44 }
45 
46 
48 private:
49  SLEngineItf engine;
50  SLObjectItf
54 
55  SLPlayItf playbackObj;
56  SLAndroidSimpleBufferQueueItf bufferQueueObj;
57 
59 public:
61  engine(nullptr), engineObj(nullptr), outputMixObj(nullptr)
62  {}
63 
65  //todo stop and destroy playback
66  }
67 
68 
70  SLresult result;
71 
72  // init engine if not yet
73  if (!engineObj) {
74  result = slCreateEngine(&engineObj, 0, NULL, 0, NULL, NULL);
75  assert(result, "Engine creation failed");
76 
77  result = (*engineObj)->Realize(engineObj, SL_BOOLEAN_FALSE);
78  assert(result, "Engine realization failed");
79  }
80 
81  if (!engine) {
82  result = (*engineObj)->GetInterface(engineObj, SL_IID_ENGINE, &engine);
83  assert(result, "Engine interface access failed");
84  }
85 
86  // create output mix
87  if (!outputMixObj) {
88  result = (*engine)->CreateOutputMix(engine, &outputMixObj, 0, NULL, NULL);
89  assert(result, "Output mix creation failed");
90  }
91 
92  // realize the output mix
93  result = (*outputMixObj)->Realize(outputMixObj, SL_BOOLEAN_FALSE);
94  assert(result, "Output mix realization failed");
95 
96  // configure buffers queue
97  SLDataLocator_AndroidSimpleBufferQueue bufferQueueConfig =
98  {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, mode.numBuffers};
99 
100  // configure format
101  SLDataFormat_PCM formatConfig = {
102  SL_DATAFORMAT_PCM,
104  (SLuint32) mode.sampleRate * 1000, //in "milliHertz"
105  (SLuint32) AUDIO_SAMPLE_SIZE[mode.sampleFormat] *8,
106  (SLuint32) AUDIO_SAMPLE_SIZE[mode.sampleFormat] *8,
107  0,
108  SL_BYTEORDER_LITTLEENDIAN
109  };
110  SLDataSource audioSrc = {&bufferQueueConfig, &formatConfig};
111 
112  // configure audio sink
113  SLDataLocator_OutputMix outputMixLocator = {SL_DATALOCATOR_OUTPUTMIX, outputMixObj};
114  SLDataSink audioSnk = {&outputMixLocator, NULL};
115 
116  // create audio player
117  const SLInterfaceID ids[1] = {SL_IID_BUFFERQUEUE};
118  const SLboolean req[1] = {SL_BOOLEAN_TRUE};
119  result = (*engine)->CreateAudioPlayer(engine, &playerObj, &audioSrc, &audioSnk, 1, ids, req);
120  assert(result, "SLES playback initialization failed: buffered player creation", mode);
121 
122  // realize audio player
123  result = (*playerObj)->Realize(playerObj, SL_BOOLEAN_FALSE);
124  assert(result, "SLES playback initialization failed: buffered player realization", mode);
125 
126  // get playback control
127  result = (*playerObj)->GetInterface(playerObj, SL_IID_PLAY, &playbackObj);
128  assert(result, "SLES playback initialization failed: playback access", mode);
129 
130  // get buffer queue
131  result = (*playerObj)->GetInterface(playerObj, SL_IID_BUFFERQUEUE, &bufferQueueObj);
132  assert(result, "SLES playback initialization failed: buffered queue ccess", mode);
133 
134  // register callback
135  result = (*bufferQueueObj)->RegisterCallback(bufferQueueObj, &playerCallback, &playback);
136  assert(result, "SLES playback initialization failed: callback registration", mode);
137 
138  // store buffer size
140  }
141 
142 
143  void start() {
144  // start playing
145  SLresult result = (*playbackObj)->SetPlayState(playbackObj, SL_PLAYSTATE_PLAYING);
146  assert(result, "SLES playback error when starting");
147  }
148 
149 
150  void stop() {
151  // start playing
152  SLresult result = (*playbackObj)->SetPlayState(playbackObj, SL_PLAYSTATE_STOPPED);
153  assert(result, "SLES playback error when stopping");
154  }
155 
156 
157  inline void pushBuffer(sample8 *buffa) {
158  (*bufferQueueObj)->Enqueue(bufferQueueObj, buffa, bufferSize);
159  }
160 };
161 
162 
163 void playerCallback(SLAndroidSimpleBufferQueueItf queue, void *data) {
164  ((Audio::BasicRealtimePlayback*)data)->bufferQueueCallbackFunc();
165 }
166 
168  backend = new SLESBackend();
169 }
170 
171 SLESPlayback::~SLESPlayback() {
172  delete backend;
173 }
174 
175 void SLESPlayback::initialize(Mode mode) {
176  backend->initialize(mode, *this);
177  Audio::BasicRealtimePlayback::initialize(mode);
178 }
179 
180 void SLESPlayback::start() {
182  backend->start();
183 }
184 
185 void SLESPlayback::stop() {
186  backend->stop();
187 }
188 
189 void SLESPlayback::pushBuffer(sample8 *buffer, int bufferIndex) {
190  backend->pushBuffer(buffer);
191 }
192 
193 #endif
msize bufferSize
size of each buffer in bytes
Communicates an error occurred during the playback.
void initialize(Audio::AbstractPlayback::Mode mode, Audio::BasicRealtimePlayback &playback)
void pushBuffer(sample8 *buffa)
SLAndroidSimpleBufferQueueItf bufferQueueObj
uint32_t msize
memory size
Definition: basic_types.h:30
const int AUDIO_SAMPLE_SIZE[]
void assert(SLresult code, const char *message)
void playerCallback(SLAndroidSimpleBufferQueueItf queue, void *data)
AudioSampleFormat sampleFormat
format of each sample
dtime sampleRate
samples per second / sample rate in Hz
unsigned char numBuffers
number of atomic buffers
unsigned char numChannels
number of channels
dtime bufferLength
length of each atomic buffer in samples
Beatmup::IntPoint result
jlong jint start
JNIEnv jlong jint mode