OpenShot Audio Library | OpenShotAudio  0.6.0
juce_TimeSliceThread.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
27 {
28 }
29 
31 {
32  stopThread (2000);
33 }
34 
35 //==============================================================================
36 void TimeSliceThread::addTimeSliceClient (TimeSliceClient* const client, int millisecondsBeforeStarting)
37 {
38  if (client != nullptr)
39  {
40  const ScopedLock sl (listLock);
41  client->nextCallTime = Time::getCurrentTime() + RelativeTime::milliseconds (millisecondsBeforeStarting);
42  clients.addIfNotAlreadyThere (client);
43  notify();
44  }
45 }
46 
48 {
49  const ScopedLock sl1 (listLock);
50 
51  // if there's a chance we're in the middle of calling this client, we need to
52  // also lock the outer lock..
53  if (clientBeingCalled == client)
54  {
55  const ScopedUnlock ul (listLock); // unlock first to get the order right..
56 
57  const ScopedLock sl2 (callbackLock);
58  const ScopedLock sl3 (listLock);
59 
60  clients.removeFirstMatchingValue (client);
61  }
62  else
63  {
64  clients.removeFirstMatchingValue (client);
65  }
66 }
67 
69 {
70  for (;;)
71  {
72  if (auto* c = getClient (0))
74  else
75  break;
76  }
77 }
78 
80 {
81  const ScopedLock sl (listLock);
82 
83  if (clients.contains (client))
84  {
85  client->nextCallTime = Time::getCurrentTime();
86  notify();
87  }
88 }
89 
91 {
92  const ScopedLock sl (listLock);
93  return clients.size();
94 }
95 
97 {
98  const ScopedLock sl (listLock);
99  return clients[i];
100 }
101 
103 {
104  const ScopedLock sl (listLock);
105  return std::any_of (clients.begin(), clients.end(), [=] (auto* registered) { return registered == c; });
106 }
107 
108 //==============================================================================
109 TimeSliceClient* TimeSliceThread::getNextClient (int index) const
110 {
111  Time soonest;
112  TimeSliceClient* client = nullptr;
113 
114  for (int i = clients.size(); --i >= 0;)
115  {
116  auto* c = clients.getUnchecked ((i + index) % clients.size());
117 
118  if (c != nullptr && (client == nullptr || c->nextCallTime < soonest))
119  {
120  client = c;
121  soonest = c->nextCallTime;
122  }
123  }
124 
125  return client;
126 }
127 
129 {
130  int index = 0;
131 
132  while (! threadShouldExit())
133  {
134  int timeToWait = 500;
135 
136  {
137  Time nextClientTime;
138  int numClients = 0;
139 
140  {
141  const ScopedLock sl2 (listLock);
142 
143  numClients = clients.size();
144  index = numClients > 0 ? ((index + 1) % numClients) : 0;
145 
146  if (auto* firstClient = getNextClient (index))
147  nextClientTime = firstClient->nextCallTime;
148  }
149 
150  if (numClients > 0)
151  {
152  auto now = Time::getCurrentTime();
153 
154  if (nextClientTime > now)
155  {
156  timeToWait = (int) jmin ((int64) 500, (nextClientTime - now).inMilliseconds());
157  }
158  else
159  {
160  timeToWait = index == 0 ? 1 : 0;
161 
162  const ScopedLock sl (callbackLock);
163 
164  {
165  const ScopedLock sl2 (listLock);
166  clientBeingCalled = getNextClient (index);
167  }
168 
169  if (clientBeingCalled != nullptr)
170  {
171  const int msUntilNextCall = clientBeingCalled->useTimeSlice();
172 
173  const ScopedLock sl2 (listLock);
174 
175  if (msUntilNextCall >= 0)
176  clientBeingCalled->nextCallTime = now + RelativeTime::milliseconds (msUntilNextCall);
177  else
178  clients.removeFirstMatchingValue (clientBeingCalled);
179 
180  clientBeingCalled = nullptr;
181  }
182  }
183  }
184  }
185 
186  if (timeToWait > 0)
187  wait (timeToWait);
188  }
189 }
190 
191 } // namespace juce
static RelativeTime milliseconds(int milliseconds) noexcept
bool wait(double timeOutMilliseconds) const
bool threadShouldExit() const
bool stopThread(int timeOutMilliseconds)
void notify() const
virtual int useTimeSlice()=0
void removeTimeSliceClient(TimeSliceClient *clientToRemove)
void addTimeSliceClient(TimeSliceClient *clientToAdd, int millisecondsBeforeStarting=0)
TimeSliceClient * getClient(int index) const
void moveToFrontOfQueue(TimeSliceClient *clientToMove)
bool contains(const TimeSliceClient *) const
TimeSliceThread(const String &threadName)
static Time JUCE_CALLTYPE getCurrentTime() noexcept
Definition: juce_Time.cpp:233