Beatmup
aaudio_playback.cpp
Go to the documentation of this file.
1 /*
2  Beatmup image and signal processing library
3  Copyright (C) 2020, 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 #include "aaudio_playback.h"
20 
21 #include <aaudio/AAudio.h>
22 
23 using namespace Beatmup;
24 using namespace Audio;
25 
26 static const int64_t ONE_SECOND_IN_NANOS = 1000 * 1000 * 1000;
27 
28 
29 aaudio_data_callback_result_t aaudioDataCallback(
30  AAudioStream *stream,
31  void *userData,
32  void *audioData,
33  int32_t numFrames
34 ) {
35  ((Android::AAudioPlayback*)userData)->pullBuffer((sample8*)audioData, numFrames);
36  return AAUDIO_CALLBACK_RESULT_CONTINUE;
37 }
38 
39 
41 private:
42  AAudioStream *stream;
43 
44  inline void check(aaudio_result_t code, const char* message) {
45  if (code < AAUDIO_OK) {
46  std::string report(message);
47  report = report + '\n' + AAudio_convertResultToText(code);
48  throw Audio::PlaybackException(message, (int)code);
49  }
50  }
51 
52 public:
53  Backend(): stream(nullptr) {}
54 
56  if (stream)
57  AAudioStream_close(stream);
58  }
59 
61  // if there is already an open stream, close it
62  if (stream) {
63  check(AAudioStream_close(stream), "Error when closing stream");
64  stream = nullptr;
65  }
66 
67  // create builder
68  AAudioStreamBuilder *builder;
69  check(AAudio_createStreamBuilder(&builder),
70  "Error when creating stream builder.");
71 
72  // set mode
73  AAudioStreamBuilder_setSampleRate(builder, mode.sampleRate);
74  AAudioStreamBuilder_setChannelCount(builder, mode.numChannels);
75  switch (mode.sampleFormat) {
76  case Int16:
77  AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_I16);
78  break;
79  case Float32:
80  AAudioStreamBuilder_setFormat(builder, AAUDIO_FORMAT_PCM_FLOAT);
81  break;
82  default:
83  throw PlaybackException("Sample format unsupported by AAudio.", 0, mode);
84 
85  }
86  AAudioStreamBuilder_setBufferCapacityInFrames(builder, mode.bufferLength);
87 
88  // tweak performance
89  AAudioStreamBuilder_setSharingMode(builder, AAUDIO_SHARING_MODE_EXCLUSIVE);
90  AAudioStreamBuilder_setDataCallback(builder, aaudioDataCallback, frontend);
91  AAudioStreamBuilder_setPerformanceMode(builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
92 
93  // open stream
94  check(AAudioStreamBuilder_openStream(builder, &stream),
95  "Error when opening stream");
96 
97 #ifdef BEATMUP_DEBUG
98  BEATMUP_DEBUG_I("AAudio stream opened %d@%d Hz, %d samples:\n"
99  " device id: %d\n"
100  " sharing mode: %d\n"
101  " performance mode: %d\n",
102  (int)mode.numChannels, (int)mode.sampleRate, (int)mode.bufferLength,
103  (int)AAudioStream_getDeviceId(stream),
104  (int)AAudioStream_getSharingMode(stream),
105  (int)AAudioStream_getPerformanceMode(stream));
106 #endif
107 
108  // clean up
109  AAudioStreamBuilder_delete(builder);
110  }
111 
112 
113  void start() {
114  check( AAudioStream_requestStart(stream),
115  "Error when requesting start of a stream");
116 
117  aaudio_stream_state_t nextState = AAUDIO_STREAM_STATE_STARTED;
118  check( AAudioStream_waitForStateChange(stream, AAUDIO_STREAM_STATE_STARTING, &nextState, ONE_SECOND_IN_NANOS),
119  "Error when starting a stream");
120  }
121 
122 
123  void stop() {
124  check( AAudioStream_requestStop(stream),
125  "Error when requesting stop of a stream");
126 
127  aaudio_stream_state_t nextState = AAUDIO_STREAM_STATE_STOPPED;
128  check( AAudioStream_waitForStateChange(stream, AAUDIO_STREAM_STATE_STOPPING, &nextState, ONE_SECOND_IN_NANOS),
129  "Error when stopping a stream");
130  }
131 };
132 
133 
135  backend = new Backend();
136 }
137 
139  delete backend;
140 }
141 
144  backend->initialize(this, mode);
145 }
146 
149  backend->start();
150 }
151 
153  backend->stop();
154 }
aaudio_data_callback_result_t aaudioDataCallback(AAudioStream *stream, void *userData, void *audioData, int32_t numFrames)
static const int64_t ONE_SECOND_IN_NANOS
void initialize(BasicRealtimePlayback *frontend, AbstractPlayback::Mode mode)
void check(aaudio_result_t code, const char *message)
void initialize(Mode mode)
Initializes the playback setting its main parameters.
OutputMode
Specifies how the output audio signal is handled by the audio backend.
void initialize(Mode mode)
Initializes the playback setting its main parameters.
virtual void start()
Starts playback.
Communicates an error occurred during the playback.
#define BEATMUP_DEBUG_I(...)
Definition: debug.h:33
@ Float32
floating point, 32 bit per sample
@ Int16
signed integer, 16 bit per sample
AudioSampleFormat sampleFormat
format of each sample
dtime sampleRate
samples per second / sample rate in Hz
unsigned char numChannels
number of channels
dtime bufferLength
length of each atomic buffer in samples
JNIEnv jlong jint mode