23
23
namespace audio_tools {
24
24
25
25
/* *
26
- * @brief Implements a simple audio player which supports the following
27
- * commands:
28
- * - begin
29
- * - play
30
- * - stop
31
- * - next
32
- * - set Volume
26
+ * @brief High-level audio playback pipeline and controller.
27
+ *
28
+ * Provides pull-driven playback from an AudioSource through optional decoding,
29
+ * volume control and click-free fades to an AudioOutput/AudioStream/Print.
30
+ *
31
+ * Features:
32
+ * - Playback control: begin, play, stop, next, previous, setIndex
33
+ * - PCM and encoded formats via AudioDecoder with dynamic audio info updates
34
+ * - Volume management (0.0–1.0) with pluggable VolumeControl
35
+ * - Auto-fade in/out to avoid pops; optional silence while inactive
36
+ * - Auto-advance on timeout with forward/backward navigation
37
+ * - Metadata: ICY (via source) or ID3 (internal MetaDataID3)
38
+ * - Callbacks: metadata updates and stream-change notification
39
+ * - Flow control: adjustable copy buffer and optional delay when output is full
40
+ *
41
+ * Pipeline: AudioSource → StreamCopy → EncodedAudioOutput → VolumeStream →
42
+ * FadeStream → Output.
43
+ *
44
+ * Operation model: call copy() regularly (non-blocking) or copyAll() for
45
+ * blocking end-to-end playback.
46
+ *
33
47
* @ingroup player
34
48
* @author Phil Schatzmann
35
49
* @copyright GPLv3
@@ -94,10 +108,13 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
94
108
decoder.addNotifyAudioChange (*this );
95
109
}
96
110
111
+ // / Non-copyable: copy constructor is deleted
97
112
AudioPlayer (AudioPlayer const &) = delete ;
98
113
114
+ // / Non-assignable: assignment operator is deleted
99
115
AudioPlayer &operator =(AudioPlayer const &) = delete ;
100
116
117
+ // / Sets the final output to an AudioOutput (adds Volume/Fade for PCM)
101
118
void setOutput (AudioOutput &output) {
102
119
if (p_decoder->isResultPCM ()) {
103
120
this ->fade .setOutput (output);
@@ -112,6 +129,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
112
129
this ->p_final_stream = nullptr ;
113
130
}
114
131
132
+ // / Sets the final output to a Print (adds Volume/Fade for PCM)
115
133
void setOutput (Print &output) {
116
134
if (p_decoder->isResultPCM ()) {
117
135
this ->fade .setOutput (output);
@@ -126,6 +144,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
126
144
this ->p_final_stream = nullptr ;
127
145
}
128
146
147
+ // / Sets the final output to an AudioStream (adds Volume/Fade for PCM)
129
148
void setOutput (AudioStream &output) {
130
149
if (p_decoder->isResultPCM ()) {
131
150
this ->fade .setOutput (output);
@@ -140,11 +159,10 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
140
159
this ->p_final_stream = &output;
141
160
}
142
161
143
- // / Defines the number of bytes used by the copier
162
+ // / Sets the internal copy buffer size (bytes)
144
163
void setBufferSize (int size) { copier.resize (size); }
145
164
146
- // / (Re)Starts the playing of the music (from the beginning or the indicated
147
- // / index)
165
+ // / Starts or restarts playback from the first or given stream index
148
166
bool begin (int index = 0 , bool isActive = true ) {
149
167
TRACED ();
150
168
bool result = false ;
@@ -200,6 +218,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
200
218
return result;
201
219
}
202
220
221
+ // / Ends playback and resets decoder/intermediate stages
203
222
void end () {
204
223
TRACED ();
205
224
active = false ;
@@ -213,19 +232,19 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
213
232
}
214
233
}
215
234
216
- // / Provides the actual audio source
235
+ // / Returns the active AudioSource
217
236
AudioSource &audioSource () { return *p_source; }
218
237
219
- // / (Re)defines the audio source
238
+ // / Sets or replaces the AudioSource
220
239
void setAudioSource (AudioSource &source) { this ->p_source = &source; }
221
240
222
- // / (Re)defines the decoder
241
+ // / Sets or replaces the AudioDecoder
223
242
void setDecoder (AudioDecoder &decoder) {
224
243
this ->p_decoder = &decoder;
225
244
out_decoding.setDecoder (p_decoder);
226
245
}
227
246
228
- // / (Re)defines the notify
247
+ // / Adds/updates a listener notified on audio info changes
229
248
void addNotifyAudioChange (AudioInfoSupport *notify) {
230
249
this ->p_final_notify = notify;
231
250
// notification for audio configuration
@@ -234,7 +253,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
234
253
}
235
254
}
236
255
237
- // / Updates the audio info in the related objects
256
+ // / Receives and forwards updated AudioInfo to the chain
238
257
void setAudioInfo (AudioInfo info) override {
239
258
TRACED ();
240
259
LOGI (" sample_rate: %d" , (int )info.sample_rate );
@@ -250,9 +269,11 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
250
269
if (p_final_notify != nullptr ) p_final_notify->setAudioInfo (info);
251
270
};
252
271
272
+ // / Returns the current AudioInfo of the playback chain
253
273
AudioInfo audioInfo () override { return info; }
254
274
255
275
// / starts / resumes the playing after calling stop(): same as setActive(true)
276
+ // / Resumes playback after stop(); equivalent to setActive(true)
256
277
void play () {
257
278
TRACED ();
258
279
setActive (true );
@@ -278,18 +299,17 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
278
299
return true ;
279
300
}
280
301
281
- // / Obsolete: use PlayPath!
302
+ // / Obsolete: use PlayPath!
282
303
bool playFile (const char *path) { return playPath (path); }
283
304
284
305
285
- // / halts the playing: same as setActive(false)
306
+ // / Halts playback; equivalent to setActive(false)
286
307
void stop () {
287
308
TRACED ();
288
309
setActive (false );
289
310
}
290
311
291
- // / moves to next file or nth next file when indicating an offset. Negative
292
- // / values are supported to move back.
312
+ // / Moves to the next/previous stream by offset (negative supported)
293
313
bool next (int offset = 1 ) {
294
314
TRACED ();
295
315
writeEnd ();
@@ -298,7 +318,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
298
318
return active;
299
319
}
300
320
301
- // / moves to the selected file position
321
+ // / Selects stream by absolute index in the source
302
322
bool setIndex (int idx) {
303
323
TRACED ();
304
324
writeEnd ();
@@ -307,7 +327,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
307
327
return active;
308
328
}
309
329
310
- // / Moves to the selected file w/o updating the actual file position
330
+ // / Selects stream by path without changing the source iterator
311
331
bool setPath (const char *path) {
312
332
TRACED ();
313
333
writeEnd ();
@@ -316,7 +336,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
316
336
return active;
317
337
}
318
338
319
- // / moves to previous file
339
+ // / Moves back by offset streams (defaults to 1)
320
340
bool previous (int offset = 1 ) {
321
341
TRACED ();
322
342
writeEnd ();
@@ -325,7 +345,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
325
345
return active;
326
346
}
327
347
328
- // / start selected input stream
348
+ // / Activates the provided Stream as current input
329
349
bool setStream (Stream *input) {
330
350
end ();
331
351
out_decoding.begin ();
@@ -341,16 +361,16 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
341
361
return p_input_stream != nullptr ;
342
362
}
343
363
344
- // / Provides the actual stream (= e.g.file)
364
+ // / Returns the currently active input Stream ( e.g., file)
345
365
Stream *getStream () { return p_input_stream; }
346
366
347
- // / determines if the player is active
367
+ // / Checks whether playback is active
348
368
bool isActive () { return active; }
349
369
350
- // / determines if the player is active
370
+ // / Boolean conversion returns isActive()
351
371
operator bool () { return isActive (); }
352
372
353
- // / The same like start() / stop()
373
+ // / Toggles playback activity; triggers fade and optional silence
354
374
void setActive (bool isActive) {
355
375
if (is_auto_fade) {
356
376
if (isActive) {
@@ -364,7 +384,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
364
384
active = isActive;
365
385
}
366
386
367
- // / sets the volume - values need to be between 0.0 and 1.0
387
+ // / Sets volume in range [ 0.0, 1.0]; updates VolumeStream
368
388
bool setVolume (float volume) override {
369
389
bool result = true ;
370
390
if (volume >= 0 .0f && volume <= 1 .0f ) {
@@ -380,22 +400,20 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
380
400
return result;
381
401
}
382
402
383
- // / Determines the actual volume
403
+ // / Returns the current volume [0.0, 1.0]
384
404
float volume () override { return current_volume; }
385
405
386
- // / Set automatically move to next file and end of current file: This is
387
- // / determined from the AudioSource. If you want to override it call this
388
- // / method after calling begin()!
406
+ // / Enables/disables auto-advance at end/timeout (overrides AudioSource)
389
407
void setAutoNext (bool next) { autonext = next; }
390
408
391
- // / Defines the wait time in ms if the target output is full
409
+ // / Sets delay (ms) to wait when output is full
392
410
void setDelayIfOutputFull (int delayMs) { delay_if_full = delayMs; }
393
411
394
412
// / Copies DEFAULT_BUFFER_SIZE (=1024 bytes) from the source to the decoder:
395
413
// / Call this method in the loop.
396
414
size_t copy () { return copy (copier.bufferSize ()); }
397
415
398
- // / Copies all the data
416
+ // / Copies until source is exhausted (blocking)
399
417
size_t copyAll () {
400
418
size_t result = 0 ;
401
419
size_t step = copy ();
@@ -406,8 +424,7 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
406
424
return result;
407
425
}
408
426
409
- // / Copies the indicated number of bytes from the source to the decoder: Call
410
- // / this method in the loop.
427
+ // / Copies the requested bytes from source to decoder (call in loop)
411
428
size_t copy (size_t bytes) {
412
429
size_t result = 0 ;
413
430
if (active) {
@@ -444,21 +461,20 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
444
461
return result;
445
462
}
446
463
447
- // / Change the VolumeControl implementation
464
+ // / Sets a custom VolumeControl implementation
448
465
void setVolumeControl (VolumeControl &vc) { volume_out.setVolumeControl (vc); }
449
466
450
- // / Provides access to the StreamCopy, so that we can register additinal
467
+ // / Provides access to StreamCopy to register additional callbacks
451
468
// / callbacks
452
469
StreamCopy &getStreamCopy () { return copier; }
453
470
454
- // / If set to true the player writes 0 values instead of no data if the player
455
- // / is inactive
471
+ // / When enabled, writes zeros while inactive to keep sinks alive
456
472
void setSilenceOnInactive (bool active) { silence_on_inactive = active; }
457
473
458
- // / Checks if silence_on_inactive has been activated (default false)
474
+ // / Returns whether silence-on-inactive is enabled
459
475
bool isSilenceOnInactive () { return silence_on_inactive; }
460
476
461
- // / Sends the requested bytes as 0 values to the output
477
+ // / Writes the requested number of zero bytes to the output
462
478
void writeSilence (size_t bytes) {
463
479
TRACEI ();
464
480
if (p_final_print != nullptr ) {
@@ -468,25 +484,22 @@ class AudioPlayer : public AudioInfoSupport, public VolumeSupport {
468
484
}
469
485
}
470
486
471
- // /// Provides the Print object to which we send the decoding result
472
- // Print *getVolumeOutput() { return &volume_out; }
473
-
474
- // / Provides the reference to the volume stream
487
+ // / Returns the VolumeStream used by the player
475
488
VolumeStream &getVolumeStream () { return volume_out; }
476
489
477
- // / Activates/deactivates the automatic fade in and fade out to prevent
478
- // / popping sounds: default is active
490
+ // / Enables/disables automatic fade in/out to prevent pops
479
491
void setAutoFade (bool active) { is_auto_fade = active; }
480
492
493
+ // / Checks whether automatic fade in/out is enabled
481
494
bool isAutoFade () { return is_auto_fade; }
482
495
483
- // / Change the default ID3 max metadata size (256)
496
+ // / Sets the maximum ID3 metadata buffer size (default 256)
484
497
void setMetaDataSize (int size) { meta_out.resize (size); }
485
498
486
- // / this is used to set the reference for the stream change callback
499
+ // / Sets a user reference passed to the stream- change callback
487
500
void setReference (void *ref) { p_reference = ref; }
488
501
489
- // / Defines the medatadata callback
502
+ // / Defines the metadata callback
490
503
void setMetadataCallback (void (*callback)(MetaDataType type, const char *str,
491
504
int len),
492
505
ID3TypeSelection sel = SELECT_ID3) {
0 commit comments