docs
Loading...
Searching...
No Matches
AudioOutput.h
Go to the documentation of this file.
1///
2/// Copyright (C) 2026 Ultralight, Inc. All rights reserved.
3/// A license is required for commercial use. https://ultralig.ht
4///
5#pragma once
7
8#if UL_HAS(MEDIA)
9
10#include <cstdint>
11
12namespace ultralight {
13
14///
15/// An audio sample format (channel count and sample rate).
16///
18 uint32_t channels; ///< Number of channels (1 = mono, 2 = stereo, 6 = 5.1, 8 = 7.1).
19 uint32_t sample_rate; ///< Sample rate in Hz (eg, 48000).
20};
21
22///
23/// The format of a new audio stream (the same as AudioFormat).
24///
26
27///
28/// User-defined audio output interface.
29///
30/// The library uses this to play the sound of `<video>` and `<audio>` elements. It decodes the
31/// audio and pushes the samples to your implementation, which plays them on a device.
32///
33/// You can provide the library with your own AudioOutput implementation so that media audio plays
34/// through your own audio engine.
35///
36/// ## Default Implementation
37///
38/// A platform-specific implementation of AudioOutput is provided for you when you call
39/// App::Create(). Its source is in the SDK's `platform` folder if you want a starting point.
40///
41/// If you are using Renderer::Create() and don't provide one, media plays without sound.
42///
43/// ## Setting the Audio Output
44///
45/// To provide your own custom AudioOutput implementation, you should inherit from this class,
46/// handle the virtual member functions, and then pass an instance of your class to
47/// Platform::set_audio_output() before calling Renderer::Create() or App::Create(). It must stay
48/// alive until the Renderer is destroyed.
49///
50/// ## Implementing an Audio Output
51///
52/// Each loaded media file plays through its own stream, identified by a `stream_id`. A stream goes
53/// through these calls:
54///
55/// 1. CreateStream() gives you the stream's sample rate and channel count.
56/// 2. PushSamples() delivers audio as it's decoded. SetVolume() and SetPaused() can come at any
57/// time.
58/// 3. Flush() discards the buffered audio when the media seeks, and new samples follow.
59/// 4. Stop() tells you no more samples are coming. A later Flush() can start the stream again (eg,
60/// when the media loops).
61/// 5. DestroyStream() frees the stream. No more calls use its `stream_id`.
62///
63/// Samples are interleaved 32-bit floats in the range [-1.0, 1.0]. If your device wants a different
64/// sample rate or channel count, resample and downmix in your implementation.
65///
66/// \parblock
67/// @warning The library calls these methods from several of its own threads, not only the
68/// Renderer's thread. PushSamples() can still be running when Flush() or Stop() is
69/// called for the same stream, so protect each stream's state.
70/// \endparblock
71///
72/// \parblock
73/// @warning When your buffer is full, PushSamples() should wait for room instead of dropping
74/// samples (the wait keeps decoding in step with playback). A waiting PushSamples() must
75/// return as soon as Flush() or Stop() is called for its stream, or the library can hang.
76/// \endparblock
77///
78/// @note GetPlaybackPosition() is optional. Implement it for the most accurate audio-video sync.
79///
80/// @pre Requires the Pro edition or higher.
81///
82/// @see Platform::set_audio_output()
83///
85 public:
86 virtual ~AudioOutput();
87
88 ///
89 /// Create a new audio stream.
90 ///
91 /// @param stream_id The id the library uses for this stream in every later call.
92 ///
93 /// @param format The sample rate and channel count of the samples you'll receive.
94 ///
95 /// @note There's no way to report a failure. If you can't create the stream, ignore later calls
96 /// with this `stream_id`.
97 ///
98 virtual void CreateStream(uint32_t stream_id, const AudioStreamFormat& format) = 0;
99
100 ///
101 /// Push decoded samples into a stream.
102 ///
103 /// @param stream_id The stream to push samples to.
104 ///
105 /// @param samples `num_frames * channels` interleaved float values.
106 ///
107 /// @param num_frames The number of frames (one sample per channel).
108 ///
109 /// @warning When your buffer is full, wait for room instead of dropping samples. Return as soon
110 /// as Flush() or Stop() is called for this stream.
111 ///
112 virtual void PushSamples(uint32_t stream_id, const float* samples,
113 uint32_t num_frames) = 0;
114
115 ///
116 /// Set the volume of a stream.
117 ///
118 /// @param stream_id The stream to change.
119 ///
120 /// @param volume The volume, from 0.0 (silent) to 1.0 (full volume).
121 ///
122 virtual void SetVolume(uint32_t stream_id, float volume) = 0;
123
124 ///
125 /// Pause or resume a stream.
126 ///
127 /// Keep the buffered samples while paused so playback resumes where it left off.
128 ///
129 /// @param stream_id The stream to pause or resume.
130 ///
131 /// @param paused `true` to pause, `false` to resume.
132 ///
133 virtual void SetPaused(uint32_t stream_id, bool paused) = 0;
134
135 ///
136 /// Discard a stream's buffered audio.
137 ///
138 /// Called when the media seeks. The next pushed sample is from the new position.
139 ///
140 /// @param stream_id The stream to flush.
141 ///
142 /// @note Leave a paused stream paused. The library resumes it when the new position is ready.
143 ///
144 virtual void Flush(uint32_t stream_id) = 0;
145
146 ///
147 /// Tell a stream that no more samples are coming.
148 ///
149 /// Samples already in your buffer can finish playing. The stream stays valid until
150 /// DestroyStream().
151 ///
152 /// @param stream_id The stream to stop.
153 ///
154 /// @warning A PushSamples() call waiting for room must return without writing its samples.
155 ///
156 virtual void Stop(uint32_t stream_id) = 0;
157
158 ///
159 /// Destroy a stream and free its resources.
160 ///
161 /// The library calls Stop() first and waits for its pushes to finish, so no PushSamples() call is
162 /// running for this stream.
163 ///
164 /// @param stream_id The stream to destroy.
165 ///
166 virtual void DestroyStream(uint32_t stream_id) = 0;
167
168 ///
169 /// Get the number of frames of a stream that have been played.
170 ///
171 /// The library uses this to keep the video in sync with the audio. Follow these rules:
172 ///
173 /// - **Count played frames.** Count frames the device has played (after its output latency, if
174 /// your backend reports it), not frames you've pushed or buffered.
175 /// - **Reset on Flush().** Flush() sets the count to zero.
176 /// - **Hold while paused.** The count must not advance while the stream is paused.
177 ///
178 /// @param stream_id The stream to query.
179 ///
180 /// @return Returns the frame count, or 0 if your backend can't report it (the library then
181 /// times the video by the wall clock, which is less precise).
182 ///
183 virtual uint64_t GetPlaybackPosition(uint32_t stream_id) { return 0; }
184
185 ///
186 /// Get the device's preferred audio format.
187 ///
188 /// @return Returns the device's preferred channel count and sample rate.
189 ///
190 virtual AudioFormat preferred_output_format() const { return { 2, 48000 }; }
191};
192
193} // namespace ultralight
194
195#endif // UL_HAS(MEDIA)
#define UExport
Definition Exports.h:22
User-defined audio output interface.
Definition AudioOutput.h:84
virtual void PushSamples(uint32_t stream_id, const float *samples, uint32_t num_frames)=0
Push decoded samples into a stream.
virtual void SetPaused(uint32_t stream_id, bool paused)=0
Pause or resume a stream.
virtual void Stop(uint32_t stream_id)=0
Tell a stream that no more samples are coming.
virtual uint64_t GetPlaybackPosition(uint32_t stream_id)
Get the number of frames of a stream that have been played.
Definition AudioOutput.h:183
virtual AudioFormat preferred_output_format() const
Get the device's preferred audio format.
Definition AudioOutput.h:190
virtual void SetVolume(uint32_t stream_id, float volume)=0
Set the volume of a stream.
virtual void CreateStream(uint32_t stream_id, const AudioStreamFormat &format)=0
Create a new audio stream.
virtual void Flush(uint32_t stream_id)=0
Discard a stream's buffered audio.
virtual void DestroyStream(uint32_t stream_id)=0
Destroy a stream and free its resources.
Root namespace for every public Ultralight type, function, and enumeration.
AudioFormat AudioStreamFormat
The format of a new audio stream (the same as AudioFormat).
Definition AudioOutput.h:25
An audio sample format (channel count and sample rate).
Definition AudioOutput.h:17
uint32_t channels
Number of channels (1 = mono, 2 = stereo, 6 = 5.1, 8 = 7.1).
Definition AudioOutput.h:18
uint32_t sample_rate
Sample rate in Hz (eg, 48000).
Definition AudioOutput.h:19