OpenShot Library | libopenshot  0.3.0
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 <thread> // for std::this_thread::sleep_for
24 #include <chrono> // for std::chrono::milliseconds
25 
26 using namespace juce;
27 
28 namespace openshot
29 {
30  // Global reference to device manager
31  AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::m_pInstance = NULL;
32 
33  // Create or Get audio device singleton with default settings (44100, 2)
34  AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::Instance()
35  {
36  return AudioDeviceManagerSingleton::Instance(44100, 2);
37  }
38 
39  // Create or Get an instance of the device manager singleton (with custom sample rate & channels)
40  AudioDeviceManagerSingleton *AudioDeviceManagerSingleton::Instance(int rate, int channels)
41  {
42  if (!m_pInstance) {
43  // Create the actual instance of device manager only once
44  m_pInstance = new AudioDeviceManagerSingleton;
45  auto* mgr = &m_pInstance->audioDeviceManager;
46 
47  // Get preferred audio device name and type (if any)
48  auto selected_device = juce::String(
49  Settings::Instance()->PLAYBACK_AUDIO_DEVICE_NAME);
50  auto selected_type = juce::String(
51  Settings::Instance()->PLAYBACK_AUDIO_DEVICE_TYPE);
52 
53  if (selected_type.isEmpty() && !selected_device.isEmpty()) {
54  // Look up type for the selected device
55  for (const auto t : mgr->getAvailableDeviceTypes()) {
56  for (const auto n : t->getDeviceNames()) {
57  if (selected_device.trim().equalsIgnoreCase(n.trim())) {
58  selected_type = t->getTypeName();
59  break;
60  }
61  }
62  if(!selected_type.isEmpty())
63  break;
64  }
65  }
66 
67  if (!selected_type.isEmpty())
68  m_pInstance->audioDeviceManager.setCurrentAudioDeviceType(selected_type, true);
69 
70  // Settings for audio device playback
71  AudioDeviceManager::AudioDeviceSetup deviceSetup = AudioDeviceManager::AudioDeviceSetup();
72  deviceSetup.sampleRate = rate;
73  deviceSetup.inputChannels = 0;
74  deviceSetup.outputChannels = channels;
75 
76  // Detect default sample rate (of default device)
77  m_pInstance->audioDeviceManager.initialiseWithDefaultDevices (0, 2);
78  m_pInstance->defaultSampleRate = m_pInstance->audioDeviceManager.getCurrentAudioDevice()->getCurrentSampleRate();
79 
80  // Initialize audio device with specific sample rate
81  juce::String audio_error = m_pInstance->audioDeviceManager.initialise (
82  0, // number of input channels
83  channels, // number of output channels
84  nullptr, // no XML settings..
85  true, // select default device on failure
86  selected_device, // preferredDefaultDeviceName
87  &deviceSetup // sample_rate & channels
88  );
89 
90  // Persist any errors detected
91  if (audio_error.isNotEmpty()) {
92  m_pInstance->initialise_error = audio_error.toStdString();
93  } else {
94  m_pInstance->initialise_error = "";
95  }
96  }
97 
98  return m_pInstance;
99  }
100 
101  // Close audio device
102  void AudioDeviceManagerSingleton::CloseAudioDevice()
103  {
104  // Close Audio Device
105  audioDeviceManager.closeAudioDevice();
106  audioDeviceManager.removeAllChangeListeners();
107  audioDeviceManager.dispatchPendingMessages();
108  }
109 
110  // Constructor
111  AudioPlaybackThread::AudioPlaybackThread(openshot::VideoCacheThread* cache)
112  : juce::Thread("audio-playback")
113  , player()
114  , transport()
115  , mixer()
116  , source(NULL)
117  , sampleRate(0.0)
118  , numChannels(0)
119  , is_playing(false)
120  , time_thread("audio-buffer")
121  , videoCache(cache)
122  {
123  }
124 
125  // Destructor
126  AudioPlaybackThread::~AudioPlaybackThread()
127  {
128  }
129 
130  // Set the reader object
131  void AudioPlaybackThread::Reader(openshot::ReaderBase *reader) {
132  if (source)
133  source->Reader(reader);
134  else {
135  // Create new audio source reader
136  auto starting_frame = 1;
137  source = new AudioReaderSource(reader, starting_frame);
138  }
139 
140  // Set local vars
141  sampleRate = reader->info.sample_rate;
142  numChannels = reader->info.channels;
143 
144  // Set video cache thread
145  source->setVideoCache(videoCache);
146 
147  // Mark as 'playing'
148  Play();
149  }
150 
151  // Get the current frame object (which is filling the buffer)
152  std::shared_ptr<openshot::Frame> AudioPlaybackThread::getFrame()
153  {
154  if (source) return source->getFrame();
155  return std::shared_ptr<openshot::Frame>();
156  }
157 
158  // Seek the audio thread
159  void AudioPlaybackThread::Seek(int64_t new_position)
160  {
161  if (source) {
162  source->Seek(new_position);
163  }
164  }
165 
166  // Play the audio
167  void AudioPlaybackThread::Play() {
168  // Start playing
169  is_playing = true;
170  }
171 
172  // Stop the audio
173  void AudioPlaybackThread::Stop() {
174  // Stop playing
175  is_playing = false;
176  }
177 
178  // Start audio thread
179  void AudioPlaybackThread::run()
180  {
181  while (!threadShouldExit())
182  {
183  if (source && !transport.isPlaying() && is_playing) {
184 
185  // Start new audio device (or get existing one)
186  AudioDeviceManagerSingleton *audioInstance = AudioDeviceManagerSingleton::Instance(sampleRate,
187  numChannels);
188  // Add callback
189  audioInstance->audioDeviceManager.addAudioCallback(&player);
190 
191  // Create TimeSliceThread for audio buffering
192  time_thread.startThread();
193 
194  // Connect source to transport
195  transport.setSource(
196  source,
197  0, // No read ahead buffer
198  &time_thread,
199  0, // Sample rate correction (none)
200  numChannels); // max channels
201  transport.setPosition(0);
202  transport.setGain(1.0);
203 
204  // Connect transport to mixer and player
205  mixer.addInputSource(&transport, false);
206  player.setSource(&mixer);
207 
208  // Start the transport
209  transport.start();
210 
211  while (!threadShouldExit() && transport.isPlaying() && is_playing)
212  std::this_thread::sleep_for(std::chrono::milliseconds(2));
213 
214  // Stop audio and shutdown transport
215  Stop();
216  transport.stop();
217 
218  // Kill previous audio
219  transport.setSource(NULL);
220 
221  player.setSource(NULL);
222  audioInstance->audioDeviceManager.removeAudioCallback(&player);
223 
224  // Remove source
225  delete source;
226  source = NULL;
227 
228  // Stop time slice thread
229  time_thread.stopThread(-1);
230  }
231  }
232 
233  }
234 }
Source file for AudioPlaybackThread class.
Header file for global Settings class.
Singleton wrapper for AudioDeviceManager (to prevent multiple instances).
static AudioDeviceManagerSingleton * Instance()
Override with default sample rate & channels (44100, 2) and no preferred audio device.
juce::AudioDeviceManager audioDeviceManager
Public device manager property.
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
The video cache class.
This namespace is the default namespace for all code in the openshot library.
Definition: Compressor.h:29
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