OpenShot Library | libopenshot 0.3.1
AudioPlaybackThread.cpp
Go to the documentation of this file.
1
10// Copyright (c) 2008-2019 OpenShot Studios, LLC
11//
12// SPDX-License-Identifier: LGPL-3.0-or-later
13
14#include "AudioPlaybackThread.h"
15#include "Settings.h"
16
17#include "../ReaderBase.h"
18#include "../RendererBase.h"
19#include "../AudioReaderSource.h"
20#include "../AudioDevices.h"
21#include "../Settings.h"
22
23#include <mutex>
24#include <thread> // for std::this_thread::sleep_for
25#include <chrono> // for std::chrono::milliseconds
26
27using namespace juce;
28
29namespace openshot
30{
31 // Global reference to device manager
32 AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::m_pInstance = NULL;
33
34 // Create or Get audio device singleton with default settings (44100, 2)
36 {
38 }
39
40 // Create or Get an instance of the device manager singleton (with custom sample rate & channels)
42 {
43 static std::mutex mutex;
44 std::lock_guard<std::mutex> lock(mutex);
45
46 if (!m_pInstance) {
47 // Create the actual instance of device manager only once
48 m_pInstance = new AudioDeviceManagerSingleton;
49 auto* mgr = &m_pInstance->audioDeviceManager;
50 AudioIODevice *foundAudioIODevice = NULL;
51 m_pInstance->initialise_error = "";
52 m_pInstance->currentAudioDevice.name = "";
53 m_pInstance->currentAudioDevice.type = "";
54 m_pInstance->defaultSampleRate = 0.0;
55
56 // Get preferred audio device type and name (if any - these can be blank)
59
60 // Find missing device type (if needed)
61 if (requested_device.type.isEmpty() && !requested_device.name.isEmpty()) {
62 for (const auto t : mgr->getAvailableDeviceTypes()) {
63 t->scanForDevices();
64 for (const auto n : t->getDeviceNames()) {
65 if (requested_device.name.trim().equalsIgnoreCase(n.trim())) {
66 requested_device.type = t->getTypeName();
67 break;
68 }
69 }
70 }
71 }
72
73 // Populate all possible device types and device names (starting with the user's requested settings)
74 std::vector<openshot::AudioDeviceInfo> devices{ { requested_device } };
75 for (const auto t : mgr->getAvailableDeviceTypes()) {
76 t->scanForDevices();
77 for (const auto n : t->getDeviceNames()) {
78 AudioDeviceInfo device = { t->getTypeName(), n.trim() };
79 devices.push_back(device);
80 }
81 }
82
83 // Loop through all device combinations (starting with the requested one)
84 for (auto attempt_device : devices) {
85 m_pInstance->currentAudioDevice = attempt_device;
86
87 // Resets everything to a default device setup
88 m_pInstance->audioDeviceManager.initialiseWithDefaultDevices(0, channels);
89
90 // Set device type (if any)
91 if (!attempt_device.type.isEmpty()) {
92 m_pInstance->audioDeviceManager.setCurrentAudioDeviceType(attempt_device.type, true);
93 }
94
95 // Settings for audio device playback
96 AudioDeviceManager::AudioDeviceSetup deviceSetup = AudioDeviceManager::AudioDeviceSetup();
97 deviceSetup.inputChannels = 0;
98 deviceSetup.outputChannels = channels;
99
100 // Loop through common sample rates, starting with the user's requested rate
101 // Not all sample rates are supported by audio devices, for example, many VMs
102 // do not support 48000 causing no audio device to be found.
103 int possible_rates[] { rate, 48000, 44100, 22050 };
104 for(int attempt_rate : possible_rates) {
105 // Update the audio device setup for the current sample rate
106 m_pInstance->defaultSampleRate = attempt_rate;
107 deviceSetup.sampleRate = attempt_rate;
108 m_pInstance->audioDeviceManager.setAudioDeviceSetup(deviceSetup, true);
109
110 // Open the audio device with specific sample rate (if possible)
111 // Not all sample rates are supported by audio devices
112 juce::String audio_error = m_pInstance->audioDeviceManager.initialise(
113 0, // number of input channels
114 channels, // number of output channels
115 nullptr, // no XML settings..
116 true, // select default device on failure
117 attempt_device.name, // preferredDefaultDeviceName
118 &deviceSetup // sample_rate & channels
119 );
120
121 // Persist any errors detected
122 m_pInstance->initialise_error = audio_error.toStdString();
123
124 // Determine if audio device was opened successfully, and matches the attempted sample rate
125 // If all rates fail to match, a default audio device and sample rate will be opened if possible
126 foundAudioIODevice = m_pInstance->audioDeviceManager.getCurrentAudioDevice();
127 if (foundAudioIODevice && foundAudioIODevice->getCurrentSampleRate() == attempt_rate) {
128 // Successfully tested a sample rate
129 break;
130 }
131 }
132
133 if (foundAudioIODevice) {
134 // Successfully opened an audio device
135 break;
136 }
137 }
138
139 }
140 return m_pInstance;
141 }
142
143 // Close audio device
145 {
146 // Close Audio Device
147 audioDeviceManager.closeAudioDevice();
148 audioDeviceManager.removeAllChangeListeners();
149 audioDeviceManager.dispatchPendingMessages();
150
151 delete m_pInstance;
152 m_pInstance = NULL;
153 }
154
155 // Constructor
156 AudioPlaybackThread::AudioPlaybackThread(openshot::VideoCacheThread* cache)
157 : juce::Thread("audio-playback")
158 , player()
159 , transport()
160 , mixer()
161 , source(NULL)
162 , sampleRate(0.0)
163 , numChannels(0)
164 , is_playing(false)
165 , time_thread("audio-buffer")
166 , videoCache(cache)
167 {
168 }
169
170 // Destructor
171 AudioPlaybackThread::~AudioPlaybackThread()
172 {
173 }
174
175 // Set the reader object
176 void AudioPlaybackThread::Reader(openshot::ReaderBase *reader) {
177 if (source)
178 source->Reader(reader);
179 else {
180 // Create new audio source reader
181 auto starting_frame = 1;
182 source = new AudioReaderSource(reader, starting_frame);
183 }
184
185 // Set local vars
186 sampleRate = reader->info.sample_rate;
187 numChannels = reader->info.channels;
188
189 // Set video cache thread
190 source->setVideoCache(videoCache);
191
192 // Mark as 'playing'
193 Play();
194 }
195
196 // Get the current frame object (which is filling the buffer)
197 std::shared_ptr<openshot::Frame> AudioPlaybackThread::getFrame()
198 {
199 if (source) return source->getFrame();
200 return std::shared_ptr<openshot::Frame>();
201 }
202
203 // Seek the audio thread
204 void AudioPlaybackThread::Seek(int64_t new_position)
205 {
206 if (source) {
207 source->Seek(new_position);
208 }
209 }
210
211 // Play the audio
212 void AudioPlaybackThread::Play() {
213 // Start playing
214 is_playing = true;
215 }
216
217 // Stop the audio
218 void AudioPlaybackThread::Stop() {
219 // Stop playing
220 is_playing = false;
221 }
222
223 // Start audio thread
224 void AudioPlaybackThread::run()
225 {
226 while (!threadShouldExit())
227 {
228 if (source && !transport.isPlaying() && is_playing) {
229 // Start new audio device (or get existing one)
230 AudioDeviceManagerSingleton *audioInstance =
231 AudioDeviceManagerSingleton::Instance(sampleRate, numChannels);
232
233 // Add callback
234 audioInstance->audioDeviceManager.addAudioCallback(&player);
235
236 // Create TimeSliceThread for audio buffering
237 time_thread.startThread();
238
239 // Connect source to transport
240 transport.setSource(
241 source,
242 0, // No read ahead buffer
243 &time_thread,
244 0, // Sample rate correction (none)
245 numChannels); // max channels
246 transport.setPosition(0);
247 transport.setGain(1.0);
248
249 // Connect transport to mixer and player
250 mixer.addInputSource(&transport, false);
251 player.setSource(&mixer);
252
253 // Start the transport
254 transport.start();
255
256 while (!threadShouldExit() && transport.isPlaying() && is_playing)
257 std::this_thread::sleep_for(std::chrono::milliseconds(2));
258
259 // Stop audio and shutdown transport
260 Stop();
261 transport.stop();
262
263 // Kill previous audio
264 transport.setSource(NULL);
265
266 player.setSource(NULL);
267 audioInstance->audioDeviceManager.removeAudioCallback(&player);
268
269 // Remove source
270 delete source;
271 source = NULL;
272
273 // Stop time slice thread
274 time_thread.stopThread(-1);
275 }
276 }
277
278 }
279}
Source file for AudioPlaybackThread class.
Header file for global Settings class.
Singleton wrapper for AudioDeviceManager (to prevent multiple instances).
double defaultSampleRate
Default sample rate (as detected)
static AudioDeviceManagerSingleton * Instance()
Override with default sample rate & channels (44100, 2) and no preferred audio device.
juce::AudioDeviceManager audioDeviceManager
Public device manager property.
AudioDeviceInfo currentAudioDevice
Current open audio device (or last attempted device - if none were successful)
std::string initialise_error
Error found during JUCE initialise method.
void Seek(int64_t new_position)
Seek to a specific frame.
void Reader(ReaderBase *audio_reader)
Set Reader.
std::shared_ptr< Frame > getFrame() const
Return the current frame object.
void setVideoCache(openshot::VideoCacheThread *newCache)
Set playback video cache thread (for pre-roll reference)
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:76
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:88
std::string PLAYBACK_AUDIO_DEVICE_NAME
The audio device name to use during playback.
Definition: Settings.h:101
std::string PLAYBACK_AUDIO_DEVICE_TYPE
The device type for the playback audio devices.
Definition: Settings.h:104
static Settings * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition: Settings.cpp:23
The video cache class.
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:29
This struct hold information about Audio Devices.
Definition: AudioDevices.h:27
int channels
The number of audio channels used in the audio stream.
Definition: ReaderBase.h:61
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:60