OpenShot Library | libopenshot  0.3.3
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 #include "../ZmqLogger.h"
23 
24 #include <mutex>
25 #include <thread> // for std::this_thread::sleep_for
26 #include <chrono> // for std::chrono::milliseconds
27 #include <sstream>
28 #include <condition_variable>
29 #include <mutex>
30 
31 using namespace juce;
32 
33 namespace openshot
34 {
35  // Global reference to device manager
36  AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::m_pInstance = NULL;
37 
38  // Create or Get audio device singleton with default settings (44100, 2)
39  AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::Instance()
40  {
41  return AudioDeviceManagerSingleton::Instance(44100, 2);
42  }
43 
44  // Create or Get an instance of the device manager singleton (with custom sample rate & channels)
45  AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::Instance(int rate, int channels)
46  {
47  static std::mutex mutex;
48  std::lock_guard<std::mutex> lock(mutex);
49 
50  if (!m_pInstance) {
51  // Create the actual instance of device manager only once
52  m_pInstance = new AudioDeviceManagerSingleton;
53  auto* mgr = &m_pInstance->audioDeviceManager;
54  AudioIODevice *foundAudioIODevice = NULL;
55  m_pInstance->initialise_error = "";
56  m_pInstance->currentAudioDevice.name = "";
57  m_pInstance->currentAudioDevice.type = "";
58  m_pInstance->defaultSampleRate = 0.0;
59 
60  std::stringstream constructor_title;
61  constructor_title << "AudioDeviceManagerSingleton::Instance (default audio device type: " <<
62  Settings::Instance()->PLAYBACK_AUDIO_DEVICE_TYPE << ", default audio device name: " <<
63  Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME << ")";
64  ZmqLogger::Instance()->AppendDebugMethod(constructor_title.str(), "channels", channels, "buffer", Settings::Instance()->PLAYBACK_AUDIO_BUFFER_SIZE);
65 
66  // Get preferred audio device type and name (if any - these can be blank)
67  openshot::AudioDeviceInfo requested_device = {Settings::Instance()->PLAYBACK_AUDIO_DEVICE_TYPE,
68  Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME};
69 
70  // Find missing device type (if needed)
71  if (requested_device.type.isEmpty() && !requested_device.name.isEmpty()) {
72  for (const auto t : mgr->getAvailableDeviceTypes()) {
73  t->scanForDevices();
74  for (const auto n : t->getDeviceNames()) {
75  if (requested_device.name.trim().equalsIgnoreCase(n.trim())) {
76  requested_device.type = t->getTypeName();
77  break;
78  }
79  }
80  }
81  }
82 
83  // Populate all possible device types and device names (starting with the user's requested settings)
84  std::vector<openshot::AudioDeviceInfo> devices{ { requested_device } };
85  for (const auto t : mgr->getAvailableDeviceTypes()) {
86  std::stringstream type_debug;
87  type_debug << "AudioDeviceManagerSingleton::Instance (iterate audio device type: " << t->getTypeName() << ")";
88  ZmqLogger::Instance()->AppendDebugMethod(type_debug.str(), "rate", rate, "channels", channels);
89 
90  t->scanForDevices();
91  for (const auto n : t->getDeviceNames()) {
92  AudioDeviceInfo device = { t->getTypeName(), n.trim() };
93  devices.push_back(device);
94  std::stringstream device_debug;
95  device_debug << "AudioDeviceManagerSingleton::Instance (iterate audio device name: " << device.name << ", type: " << t->getTypeName() << ")";
96  ZmqLogger::Instance()->AppendDebugMethod(device_debug.str(), "rate", rate, "channels", channels);
97  }
98  }
99 
100  // Loop through all device combinations (starting with the requested one)
101  for (auto attempt_device : devices) {
102  m_pInstance->currentAudioDevice = attempt_device;
103 
104  // Resets everything to a default device setup
105  m_pInstance->audioDeviceManager.initialiseWithDefaultDevices(0, channels);
106 
107  // Set device type (if any)
108  if (!attempt_device.type.isEmpty()) {
109  m_pInstance->audioDeviceManager.setCurrentAudioDeviceType(attempt_device.type, true);
110  }
111 
112  // Settings for audio device playback
113  AudioDeviceManager::AudioDeviceSetup deviceSetup = AudioDeviceManager::AudioDeviceSetup();
114  deviceSetup.inputChannels = 0;
115  deviceSetup.outputChannels = channels;
116  deviceSetup.bufferSize = Settings::Instance()->PLAYBACK_AUDIO_BUFFER_SIZE;
117 
118  // Loop through common sample rates, starting with the user's requested rate
119  // Not all sample rates are supported by audio devices, for example, many VMs
120  // do not support 48000 causing no audio device to be found.
121  int possible_rates[] { rate, 48000, 44100, 22050 };
122  for(int attempt_rate : possible_rates) {
123  std::stringstream title_rate;
124  title_rate << "AudioDeviceManagerSingleton::Instance (attempt audio device name: " << attempt_device.name << ")";
125  ZmqLogger::Instance()->AppendDebugMethod(title_rate.str(), "rate", attempt_rate, "channels", channels);
126 
127  // Update the audio device setup for the current sample rate
128  m_pInstance->defaultSampleRate = attempt_rate;
129  deviceSetup.sampleRate = attempt_rate;
130  m_pInstance->audioDeviceManager.setAudioDeviceSetup(deviceSetup, true);
131 
132  // Open the audio device with specific sample rate (if possible)
133  // Not all sample rates are supported by audio devices
134  juce::String audio_error = m_pInstance->audioDeviceManager.initialise(
135  0, // number of input channels
136  channels, // number of output channels
137  nullptr, // no XML settings..
138  true, // select default device on failure
139  attempt_device.name, // preferredDefaultDeviceName
140  &deviceSetup // sample_rate & channels
141  );
142 
143  // Persist any errors detected
144  m_pInstance->initialise_error = audio_error.toStdString();
145 
146  if (!m_pInstance->initialise_error.empty()) {
147  std::stringstream title_error;
148  title_error << "AudioDeviceManagerSingleton::Instance (audio device error: " <<
149  m_pInstance->initialise_error << ")";
150  ZmqLogger::Instance()->AppendDebugMethod(title_error.str(), "rate", attempt_rate, "channels", channels);
151  }
152 
153  // Determine if audio device was opened successfully, and matches the attempted sample rate
154  // If all rates fail to match, a default audio device and sample rate will be opened if possible
155  foundAudioIODevice = m_pInstance->audioDeviceManager.getCurrentAudioDevice();
156  if (foundAudioIODevice && foundAudioIODevice->getCurrentSampleRate() == attempt_rate) {
157  // Successfully tested a sample rate
158  std::stringstream title_found;
159  title_found << "AudioDeviceManagerSingleton::Instance (successful audio device found: " <<
160  foundAudioIODevice->getTypeName() << ", name: " << foundAudioIODevice->getName() << ")";
161  ZmqLogger::Instance()->AppendDebugMethod(title_found.str(), "rate", attempt_rate, "channels", channels);
162  break;
163  }
164  }
165 
166  if (foundAudioIODevice) {
167  // Successfully opened an audio device
168  break;
169  }
170  }
171 
172  ZmqLogger::Instance()->AppendDebugMethod("AudioDeviceManagerSingleton::Instance (audio device initialization completed)");
173  }
174  return m_pInstance;
175  }
176 
177  // Close audio device
178  void AudioDeviceManagerSingleton::CloseAudioDevice()
179  {
180  // Close Audio Device
181  audioDeviceManager.closeAudioDevice();
182  audioDeviceManager.removeAllChangeListeners();
183  audioDeviceManager.dispatchPendingMessages();
184 
185  delete m_pInstance;
186  m_pInstance = NULL;
187  }
188 
189  // Constructor
190  AudioPlaybackThread::AudioPlaybackThread(openshot::VideoCacheThread* cache)
191  : juce::Thread("audio-playback")
192  , player()
193  , transport()
194  , mixer()
195  , source(NULL)
196  , sampleRate(0.0)
197  , numChannels(0)
198  , is_playing(false)
199  , time_thread("audio-buffer")
200  , videoCache(cache)
201  {
202  }
203 
204  // Destructor
205  AudioPlaybackThread::~AudioPlaybackThread()
206  {
207  }
208 
209  // Set the reader object
210  void AudioPlaybackThread::Reader(openshot::ReaderBase *reader) {
211  if (source)
212  source->Reader(reader);
213  else {
214  // Create new audio source reader
215  auto starting_frame = 1;
216  source = new AudioReaderSource(reader, starting_frame);
217  }
218 
219  // Set local vars
220  sampleRate = reader->info.sample_rate;
221  numChannels = reader->info.channels;
222 
223  ZmqLogger::Instance()->AppendDebugMethod("AudioPlaybackThread::Reader", "rate", sampleRate, "channel", numChannels);
224 
225  // Set video cache thread
226  source->setVideoCache(videoCache);
227 
228  // Mark as 'playing'
229  Play();
230  }
231 
232  // Get the current frame object (which is filling the buffer)
233  std::shared_ptr<openshot::Frame> AudioPlaybackThread::getFrame()
234  {
235  if (source) return source->getFrame();
236  return std::shared_ptr<openshot::Frame>();
237  }
238 
239  // Seek the audio thread
240  void AudioPlaybackThread::Seek(int64_t new_position)
241  {
242  if (source) {
243  source->Seek(new_position);
244  }
245  }
246 
247  // Override Play and Stop to notify of state changes
248  void AudioPlaybackThread::Play() {
249  is_playing = true;
250  NotifyTransportStateChanged();
251  }
252 
253  void AudioPlaybackThread::Stop() {
254  is_playing = false;
255  NotifyTransportStateChanged();
256  }
257 
258  void AudioPlaybackThread::NotifyTransportStateChanged()
259  {
260  std::lock_guard<std::mutex> lock(transportMutex);
261  transportCondition.notify_all();
262  }
263 
264  // Start audio thread
265  void AudioPlaybackThread::run()
266  {
267  while (!threadShouldExit())
268  {
269  if (source && !transport.isPlaying() && is_playing) {
270  // Start new audio device (or get existing one)
271  AudioDeviceManagerSingleton *audioInstance =
272  AudioDeviceManagerSingleton::Instance(sampleRate, numChannels);
273 
274  // Add callback
275  audioInstance->audioDeviceManager.addAudioCallback(&player);
276 
277  // Create TimeSliceThread for audio buffering
278  time_thread.startThread(Priority::high);
279 
280  // Connect source to transport
281  transport.setSource(
282  source,
283  0, // No read ahead buffer
284  &time_thread,
285  0, // Sample rate correction (none)
286  numChannels); // max channels
287  transport.setPosition(0);
288  transport.setGain(1.0);
289 
290  // Connect transport to mixer and player
291  mixer.addInputSource(&transport, false);
292  player.setSource(&mixer);
293 
294  // Start the transport
295  transport.start();
296 
297  while (!threadShouldExit() && transport.isPlaying() && is_playing) {
298  // Wait until transport state changes or thread should exit
299  std::unique_lock<std::mutex> lock(transportMutex);
300  transportCondition.wait_for(lock, std::chrono::milliseconds(10), [this]() {
301  return threadShouldExit() || !transport.isPlaying() || !is_playing;
302  });
303  }
304 
305  // Stop audio and shutdown transport
306  Stop();
307  transport.stop();
308 
309  // Kill previous audio
310  transport.setSource(NULL);
311 
312  player.setSource(NULL);
313  audioInstance->audioDeviceManager.removeAudioCallback(&player);
314 
315  // Remove source
316  delete source;
317  source = NULL;
318 
319  // Stop time slice thread
320  time_thread.stopThread(-1);
321  }
322  }
323 
324  }
325 }
Settings.h
Header file for global Settings class.
openshot::AudioReaderSource::Seek
void Seek(int64_t new_position)
Seek to a specific frame.
Definition: AudioReaderSource.h:97
openshot::ReaderInfo::sample_rate
int sample_rate
The number of audio samples per second (44100 is a common sample rate)
Definition: ReaderBase.h:60
openshot::AudioDeviceInfo
This struct hold information about Audio Devices.
Definition: AudioDevices.h:26
openshot
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:28
openshot::AudioDeviceManagerSingleton::Instance
static AudioDeviceManagerSingleton * Instance()
Override with default sample rate & channels (44100, 2) and no preferred audio device.
Definition: AudioPlaybackThread.cpp:39
openshot::AudioDeviceManagerSingleton::audioDeviceManager
juce::AudioDeviceManager audioDeviceManager
Public device manager property.
Definition: AudioPlaybackThread.h:68
openshot::ReaderBase::info
openshot::ReaderInfo info
Information about the current media file.
Definition: ReaderBase.h:88
openshot::AudioDeviceInfo::name
juce::String name
Definition: AudioDevices.h:29
openshot::AudioReaderSource::setVideoCache
void setVideoCache(openshot::VideoCacheThread *newCache)
Set playback video cache thread (for pre-roll reference)
Definition: AudioReaderSource.h:89
openshot::AudioDeviceInfo::type
juce::String type
Definition: AudioDevices.h:28
openshot::AudioDeviceManagerSingleton
Singleton wrapper for AudioDeviceManager (to prevent multiple instances).
Definition: AudioPlaybackThread.h:42
openshot::VideoCacheThread
The video cache class.
Definition: VideoCacheThread.h:29
juce
Definition: Robotization.h:29
AudioPlaybackThread.h
Source file for AudioPlaybackThread class.
openshot::ZmqLogger::Instance
static ZmqLogger * Instance()
Create or get an instance of this logger singleton (invoke the class with this method)
Definition: ZmqLogger.cpp:35
openshot::AudioReaderSource::Reader
void Reader(ReaderBase *audio_reader)
Set Reader.
Definition: AudioReaderSource.h:92
openshot::ZmqLogger::AppendDebugMethod
void AppendDebugMethod(std::string method_name, std::string arg1_name="", float arg1_value=-1.0, std::string arg2_name="", float arg2_value=-1.0, std::string arg3_name="", float arg3_value=-1.0, std::string arg4_name="", float arg4_value=-1.0, std::string arg5_name="", float arg5_value=-1.0, std::string arg6_name="", float arg6_value=-1.0)
Append debug information.
Definition: ZmqLogger.cpp:178
openshot::AudioReaderSource::getFrame
std::shared_ptr< Frame > getFrame() const
Return the current frame object.
Definition: AudioReaderSource.h:81
openshot::ReaderBase
This abstract class is the base class, used by all readers in libopenshot.
Definition: ReaderBase.h:75
openshot::ReaderInfo::channels
int channels
The number of audio channels used in the audio stream.
Definition: ReaderBase.h:61