mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Updates to support the latest Oboe (c5c3cc17f78974bf005bf33a2de1a093ac55cc07).
This commit is contained in:
parent
c4663b5aec
commit
2718ce96f0
2 changed files with 150 additions and 133 deletions
|
|
@ -881,7 +881,7 @@ private:
|
|||
{
|
||||
props.add (new TextPropertyComponent (androidOboeRepositoryPath, "Oboe Repository Path", 2048, false),
|
||||
"Path to the root of Oboe repository. Make sure to point Oboe repository to "
|
||||
"commit with SHA 44c6b6ea9c8fa9b5b74cbd60f355068b57b50b37 before building.");
|
||||
"commit with SHA c5c3cc17f78974bf005bf33a2de1a093ac55cc07 before building.");
|
||||
|
||||
props.add (new ChoicePropertyComponent (androidInternetNeeded, "Internet Access"),
|
||||
"If enabled, this will set the android.permission.INTERNET flag in the manifest.");
|
||||
|
|
|
|||
|
|
@ -124,6 +124,12 @@ struct OboeAudioIODeviceBufferHelpers<float>
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
static String getOboeString (const Type& value)
|
||||
{
|
||||
return String (oboe::convertToText (value));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class OboeAudioIODevice : public AudioIODevice
|
||||
|
|
@ -438,8 +444,8 @@ private:
|
|||
|
||||
~OboeStream()
|
||||
{
|
||||
// AudioStreamCallback can only be deleted when stream has been closed
|
||||
close();
|
||||
delete stream;
|
||||
}
|
||||
|
||||
bool openedOk() const noexcept
|
||||
|
|
@ -458,40 +464,47 @@ private:
|
|||
int64 timeoutNanos = 1000 * oboe::kNanosPerMillisecond;
|
||||
|
||||
auto startResult = stream->requestStart();
|
||||
JUCE_OBOE_LOG ("Requested Oboe stream start with result: " + String (oboe::convertToText (startResult)));
|
||||
JUCE_OBOE_LOG ("Requested Oboe stream start with result: " + getOboeString (startResult));
|
||||
|
||||
startResult = stream->waitForStateChange (expectedState, &nextState, timeoutNanos);
|
||||
JUCE_OBOE_LOG ("Starting Oboe stream with result: " + String (oboe::convertToText (startResult));
|
||||
+ "\nUses AAudio = " + (stream != nullptr ? String ((int) stream->usesAAudio()) : String ("?"))
|
||||
+ "\nDirection = " + (stream != nullptr ? String (oboe::convertToText (stream->getDirection())) : String ("?"))
|
||||
+ "\nSharingMode = " + (stream != nullptr ? String (oboe::convertToText (stream->getSharingMode())) : String ("?"))
|
||||
+ "\nChannelCount = " + (stream != nullptr ? String (stream->getChannelCount()) : String ("?"))
|
||||
+ "\nFormat = " + (stream != nullptr ? String (oboe::convertToText (stream->getFormat())) : String ("?"))
|
||||
+ "\nSampleRate = " + (stream != nullptr ? String (stream->getSampleRate()) : String ("?"))
|
||||
+ "\nBufferSizeInFrames = " + (stream != nullptr ? String (stream->getBufferSizeInFrames()) : String ("?"))
|
||||
+ "\nBufferCapacityInFrames = " + (stream != nullptr ? String (stream->getBufferCapacityInFrames()) : String ("?"))
|
||||
+ "\nFramesPerBurst = " + (stream != nullptr ? String (stream->getFramesPerBurst()) : String ("?"))
|
||||
+ "\nFramesPerCallback = " + (stream != nullptr ? String (stream->getFramesPerCallback()) : String ("?"))
|
||||
+ "\nBytesPerFrame = " + (stream != nullptr ? String (stream->getBytesPerFrame()) : String ("?"))
|
||||
+ "\nBytesPerSample = " + (stream != nullptr ? String (stream->getBytesPerSample()) : String ("?"))
|
||||
+ "\nPerformanceMode = " + String (oboe::convertToText (oboe::PerformanceMode::LowLatency))
|
||||
+ "\ngetDeviceId = " + (stream != nullptr ? String (stream->getDeviceId()) : String ("?")));
|
||||
startResult = stream->waitForStateChange (expectedState, &nextState, timeoutNanos);
|
||||
|
||||
JUCE_OBOE_LOG ("Starting Oboe stream with result: " + getOboeString (startResult);
|
||||
+ "\nUses AAudio = " + String ((int) stream->usesAAudio())
|
||||
+ "\nDirection = " + getOboeString (stream->getDirection())
|
||||
+ "\nSharingMode = " + getOboeString (stream->getSharingMode())
|
||||
+ "\nChannelCount = " + String (stream->getChannelCount())
|
||||
+ "\nFormat = " + getOboeString (stream->getFormat())
|
||||
+ "\nSampleRate = " + String (stream->getSampleRate())
|
||||
+ "\nBufferSizeInFrames = " + String (stream->getBufferSizeInFrames())
|
||||
+ "\nBufferCapacityInFrames = " + String (stream->getBufferCapacityInFrames())
|
||||
+ "\nFramesPerBurst = " + String (stream->getFramesPerBurst())
|
||||
+ "\nFramesPerCallback = " + String (stream->getFramesPerCallback())
|
||||
+ "\nBytesPerFrame = " + String (stream->getBytesPerFrame())
|
||||
+ "\nBytesPerSample = " + String (stream->getBytesPerSample())
|
||||
+ "\nPerformanceMode = " + getOboeString (oboe::PerformanceMode::LowLatency)
|
||||
+ "\ngetDeviceId = " + String (stream->getDeviceId()));
|
||||
}
|
||||
}
|
||||
|
||||
oboe::AudioStream* getNativeStream()
|
||||
oboe::AudioStream* getNativeStream() const
|
||||
{
|
||||
jassert (openedOk());
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
int getXRunCount() const
|
||||
{
|
||||
if (auto xruns = stream->getXRunCount())
|
||||
return xruns.value();
|
||||
if (stream != nullptr)
|
||||
{
|
||||
auto count = stream->getXRunCount();
|
||||
|
||||
if (count)
|
||||
return count.value();
|
||||
|
||||
JUCE_OBOE_LOG ("Failed to get Xrun count: " + getOboeString (count.error()));
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -501,39 +514,38 @@ private:
|
|||
int32 sampleRate, int32 bufferSize,
|
||||
oboe::AudioStreamCallback* callback = nullptr)
|
||||
{
|
||||
oboe::DefaultStreamValues::FramesPerBurst = getDefaultFramesPerBurst();
|
||||
|
||||
oboe::AudioStreamBuilder builder;
|
||||
|
||||
if (deviceId != -1)
|
||||
builder.setDeviceId (deviceId);
|
||||
|
||||
static int defaultFramesPerBurst = getDefaultFramesPerBurst();
|
||||
|
||||
// Note: Letting OS to choose the buffer capacity & frames per callback.
|
||||
// Note: letting OS to choose the buffer capacity & frames per callback.
|
||||
builder.setDirection (direction);
|
||||
builder.setSharingMode (sharingMode);
|
||||
builder.setChannelCount (channelCount);
|
||||
builder.setFormat (format);
|
||||
builder.setSampleRate (sampleRate);
|
||||
builder.setFramesPerCallback ((int32) defaultFramesPerBurst);
|
||||
builder.setPerformanceMode (oboe::PerformanceMode::LowLatency);
|
||||
builder.setCallback (callback);
|
||||
|
||||
JUCE_OBOE_LOG (String ("Preparing Oboe stream with params:")
|
||||
+ "\nAAudio supported = " + String (int (builder.isAAudioSupported()))
|
||||
+ "\nAPI = " + String (oboe::convertToText (builder.getAudioApi()))
|
||||
+ "\nAPI = " + getOboeString (builder.getAudioApi())
|
||||
+ "\nDeviceId = " + String (deviceId)
|
||||
+ "\nDirection = " + String (oboe::convertToText (direction))
|
||||
+ "\nSharingMode = " + String (oboe::convertToText (sharingMode))
|
||||
+ "\nDirection = " + getOboeString (direction)
|
||||
+ "\nSharingMode = " + getOboeString (sharingMode)
|
||||
+ "\nChannelCount = " + String (channelCount)
|
||||
+ "\nFormat = " + String (oboe::convertToText (format))
|
||||
+ "\nFormat = " + getOboeString (format)
|
||||
+ "\nSampleRate = " + String (sampleRate)
|
||||
+ "\nBufferSizeInFrames = " + String (bufferSize)
|
||||
+ "\nFramesPerBurst = " + String (defaultFramesPerBurst)
|
||||
+ "\nPerformanceMode = " + String (oboe::convertToText (oboe::PerformanceMode::LowLatency)));
|
||||
+ "\nFramesPerBurst = " + String (oboe::DefaultStreamValues::FramesPerBurst)
|
||||
+ "\nPerformanceMode = " + getOboeString (oboe::PerformanceMode::LowLatency));
|
||||
|
||||
openResult = builder.openStream (&stream);
|
||||
JUCE_OBOE_LOG ("Building Oboe stream with result: " + String (oboe::convertToText (openResult))
|
||||
+ "\nStream state = " + (stream != nullptr ? String (oboe::convertToText (stream->getState())) : String ("?")));
|
||||
JUCE_OBOE_LOG ("Building Oboe stream with result: " + getOboeString (openResult)
|
||||
+ "\nStream state = " + (stream != nullptr ? getOboeString (stream->getState()) : String ("?")));
|
||||
|
||||
if (stream != nullptr)
|
||||
stream->setBufferSizeInFrames (bufferSize);
|
||||
|
|
@ -541,10 +553,10 @@ private:
|
|||
JUCE_OBOE_LOG (String ("Stream details:")
|
||||
+ "\nUses AAudio = " + (stream != nullptr ? String ((int) stream->usesAAudio()) : String ("?"))
|
||||
+ "\nDeviceId = " + (stream != nullptr ? String (stream->getDeviceId()) : String ("?"))
|
||||
+ "\nDirection = " + (stream != nullptr ? String (oboe::convertToText (stream->getDirection())) : String ("?"))
|
||||
+ "\nSharingMode = " + (stream != nullptr ? String (oboe::convertToText (stream->getSharingMode())) : String ("?"))
|
||||
+ "\nDirection = " + (stream != nullptr ? getOboeString (stream->getDirection()) : String ("?"))
|
||||
+ "\nSharingMode = " + (stream != nullptr ? getOboeString (stream->getSharingMode()) : String ("?"))
|
||||
+ "\nChannelCount = " + (stream != nullptr ? String (stream->getChannelCount()) : String ("?"))
|
||||
+ "\nFormat = " + (stream != nullptr ? String (oboe::convertToText (stream->getFormat())) : String ("?"))
|
||||
+ "\nFormat = " + (stream != nullptr ? getOboeString (stream->getFormat()) : String ("?"))
|
||||
+ "\nSampleRate = " + (stream != nullptr ? String (stream->getSampleRate()) : String ("?"))
|
||||
+ "\nBufferSizeInFrames = " + (stream != nullptr ? String (stream->getBufferSizeInFrames()) : String ("?"))
|
||||
+ "\nBufferCapacityInFrames = " + (stream != nullptr ? String (stream->getBufferCapacityInFrames()) : String ("?"))
|
||||
|
|
@ -552,7 +564,7 @@ private:
|
|||
+ "\nFramesPerCallback = " + (stream != nullptr ? String (stream->getFramesPerCallback()) : String ("?"))
|
||||
+ "\nBytesPerFrame = " + (stream != nullptr ? String (stream->getBytesPerFrame()) : String ("?"))
|
||||
+ "\nBytesPerSample = " + (stream != nullptr ? String (stream->getBytesPerSample()) : String ("?"))
|
||||
+ "\nPerformanceMode = " + String (oboe::convertToText (oboe::PerformanceMode::LowLatency)));
|
||||
+ "\nPerformanceMode = " + getOboeString (oboe::PerformanceMode::LowLatency));
|
||||
}
|
||||
|
||||
void close()
|
||||
|
|
@ -560,27 +572,10 @@ private:
|
|||
if (stream != nullptr)
|
||||
{
|
||||
oboe::Result result = stream->close();
|
||||
JUCE_OBOE_LOG ("Requested Oboe stream close with result: " + String (oboe::convertToText (result)));
|
||||
JUCE_OBOE_LOG ("Requested Oboe stream close with result: " + getOboeString (result));
|
||||
}
|
||||
}
|
||||
|
||||
int getDefaultFramesPerBurst() const
|
||||
{
|
||||
// NB: this function only works for inbuilt speakers and headphones
|
||||
auto* env = getEnv();
|
||||
|
||||
auto audioManager = LocalRef<jobject> (env->CallObjectMethod (android.activity,
|
||||
JuceAppActivity.getSystemService,
|
||||
javaString ("audio").get()));
|
||||
|
||||
auto propertyJavaString = javaString ("android.media.property.OUTPUT_FRAMES_PER_BUFFER");
|
||||
|
||||
auto framesPerBurstString = LocalRef<jstring> ((jstring) android.activity.callObjectMethod (JuceAppActivity.audioManagerGetProperty,
|
||||
propertyJavaString.get()));
|
||||
|
||||
return framesPerBurstString != 0 ? env->CallStaticIntMethod (JavaInteger, JavaInteger.parseInt, framesPerBurstString.get(), 10) : 192;
|
||||
}
|
||||
|
||||
oboe::AudioStream* stream = nullptr;
|
||||
oboe::Result openResult;
|
||||
};
|
||||
|
|
@ -672,9 +667,7 @@ private:
|
|||
void checkStreamSetup (OboeStream* stream, int deviceId, int numChannels, int sampleRate,
|
||||
int bufferSize, oboe::AudioFormat format)
|
||||
{
|
||||
auto* nativeStream = stream != nullptr ? stream->getNativeStream() : nullptr;
|
||||
|
||||
if (nativeStream != nullptr)
|
||||
if (auto* nativeStream = stream != nullptr ? stream->getNativeStream() : nullptr)
|
||||
{
|
||||
ignoreUnused (deviceId, numChannels, sampleRate, bufferSize);
|
||||
ignoreUnused (streamFormat, bitDepth);
|
||||
|
|
@ -739,7 +732,8 @@ private:
|
|||
|
||||
outputStream->start();
|
||||
|
||||
checkIsOutputLatencyDetectionSupported();
|
||||
isInputLatencyDetectionSupported = isLatencyDetectionSupported (inputStream.get());
|
||||
isOutputLatencyDetectionSupported = isLatencyDetectionSupported (outputStream.get());
|
||||
}
|
||||
|
||||
void stop() override
|
||||
|
|
@ -754,19 +748,16 @@ private:
|
|||
}
|
||||
|
||||
int getOutputLatencyInSamples() override { return outputLatency; }
|
||||
int getInputLatencyInSamples() override { return -1; }
|
||||
int getInputLatencyInSamples() override { return inputLatency; }
|
||||
|
||||
private:
|
||||
void checkIsOutputLatencyDetectionSupported()
|
||||
bool isLatencyDetectionSupported (OboeStream* stream)
|
||||
{
|
||||
if (! openedOk())
|
||||
{
|
||||
isOutputLatencyDetectionSupported = false;
|
||||
return;
|
||||
}
|
||||
if (stream == nullptr || ! openedOk())
|
||||
return false;
|
||||
|
||||
auto result = outputStream->getNativeStream()->getTimestamp (CLOCK_MONOTONIC, 0, 0);
|
||||
isOutputLatencyDetectionSupported = result != oboe::Result::ErrorUnimplemented;
|
||||
auto result = stream->getNativeStream()->getTimestamp (CLOCK_MONOTONIC, 0, 0);
|
||||
return result != oboe::Result::ErrorUnimplemented;
|
||||
}
|
||||
|
||||
oboe::DataCallbackResult onAudioReady (oboe::AudioStream* stream, void* audioData, int32_t numFrames) override
|
||||
|
|
@ -792,7 +783,7 @@ private:
|
|||
|
||||
if (nativeInputStream->getFormat() != oboe::AudioFormat::I16 && nativeInputStream->getFormat() != oboe::AudioFormat::Float)
|
||||
{
|
||||
JUCE_OBOE_LOG ("Unsupported input stream audio format: " + String (oboe::convertToText (nativeInputStream->getFormat())));
|
||||
JUCE_OBOE_LOG ("Unsupported input stream audio format: " + getOboeString (nativeInputStream->getFormat()));
|
||||
jassertfalse;
|
||||
return oboe::DataCallbackResult::Continue;
|
||||
}
|
||||
|
|
@ -809,9 +800,11 @@ private:
|
|||
}
|
||||
else
|
||||
{
|
||||
// Failed to read from input stream.
|
||||
jassertfalse;
|
||||
JUCE_OBOE_LOG ("Failed to read from input stream: " + getOboeString (result.error()));
|
||||
}
|
||||
|
||||
if (isInputLatencyDetectionSupported)
|
||||
inputLatency = getLatencyFor (*inputStream);
|
||||
}
|
||||
|
||||
//-----------------
|
||||
|
|
@ -834,7 +827,7 @@ private:
|
|||
OboeAudioIODeviceBufferHelpers<SampleType>::convertToOboe (outputStreamSampleBuffer, static_cast<SampleType*> (audioData), numFrames);
|
||||
|
||||
if (isOutputLatencyDetectionSupported)
|
||||
calculateOutputLatency();
|
||||
outputLatency = getLatencyFor (*outputStream);
|
||||
|
||||
audioCallbackGuard.set (0);
|
||||
}
|
||||
|
|
@ -847,10 +840,10 @@ private:
|
|||
ignoreUnused (stream);
|
||||
|
||||
JUCE_OBOE_LOG ("\nUses AAudio = " + (stream != nullptr ? String ((int) stream->usesAAudio()) : String ("?"))
|
||||
+ "\nDirection = " + (stream != nullptr ? String (oboe::convertToText (stream->getDirection())) : String ("?"))
|
||||
+ "\nSharingMode = " + (stream != nullptr ? String (oboe::convertToText (stream->getSharingMode())) : String ("?"))
|
||||
+ "\nDirection = " + (stream != nullptr ? getOboeString (stream->getDirection()) : String ("?"))
|
||||
+ "\nSharingMode = " + (stream != nullptr ? getOboeString (stream->getSharingMode()) : String ("?"))
|
||||
+ "\nChannelCount = " + (stream != nullptr ? String (stream->getChannelCount()) : String ("?"))
|
||||
+ "\nFormat = " + (stream != nullptr ? String (oboe::convertToText (stream->getFormat())) : String ("?"))
|
||||
+ "\nFormat = " + (stream != nullptr ? getOboeString (stream->getFormat()) : String ("?"))
|
||||
+ "\nSampleRate = " + (stream != nullptr ? String (stream->getSampleRate()) : String ("?"))
|
||||
+ "\nBufferSizeInFrames = " + (stream != nullptr ? String (stream->getBufferSizeInFrames()) : String ("?"))
|
||||
+ "\nBufferCapacityInFrames = " + (stream != nullptr ? String (stream->getBufferCapacityInFrames()) : String ("?"))
|
||||
|
|
@ -858,34 +851,48 @@ private:
|
|||
+ "\nFramesPerCallback = " + (stream != nullptr ? String (stream->getFramesPerCallback()) : String ("?"))
|
||||
+ "\nBytesPerFrame = " + (stream != nullptr ? String (stream->getBytesPerFrame()) : String ("?"))
|
||||
+ "\nBytesPerSample = " + (stream != nullptr ? String (stream->getBytesPerSample()) : String ("?"))
|
||||
+ "\nPerformanceMode = " + String (oboe::convertToText (oboe::PerformanceMode::LowLatency))
|
||||
+ "\nPerformanceMode = " + getOboeString (oboe::PerformanceMode::LowLatency)
|
||||
+ "\ngetDeviceId = " + (stream != nullptr ? String (stream->getDeviceId()) : String ("?")));
|
||||
}
|
||||
|
||||
void calculateOutputLatency()
|
||||
int getLatencyFor (OboeStream& stream)
|
||||
{
|
||||
// Sadly, Oboe uses non-portable int64_t (a.k.a. long on LP64 and long long on LLP64)
|
||||
int64_t lastWrittenAndPresentedFrameIndex = 0;
|
||||
int64_t lastFramePresentationTimeNanos = 0;
|
||||
auto& nativeStream = *stream.getNativeStream();
|
||||
|
||||
auto result = outputStream->getNativeStream()->getTimestamp (CLOCK_MONOTONIC,
|
||||
&lastWrittenAndPresentedFrameIndex,
|
||||
&lastFramePresentationTimeNanos);
|
||||
if (auto latency = nativeStream.calculateLatencyMillis())
|
||||
return static_cast<int> ((latency.value() * sampleRate) / 1000);
|
||||
|
||||
// Get the time that a known audio frame was presented.
|
||||
int64_t hardwareFrameIndex = 0;
|
||||
int64_t hardwareFrameHardwareTime = 0;
|
||||
|
||||
auto result = nativeStream.getTimestamp (CLOCK_MONOTONIC,
|
||||
&hardwareFrameIndex,
|
||||
&hardwareFrameHardwareTime);
|
||||
|
||||
if (result != oboe::Result::OK)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
int64_t currentNumFramesWritten = outputStream->getNativeStream()->getFramesWritten();
|
||||
int64_t framesDelta = currentNumFramesWritten - lastWrittenAndPresentedFrameIndex;
|
||||
int64_t timeDeltaNanos = framesDelta * oboe::kNanosPerSecond / sampleRate;
|
||||
// Get counter closest to the app.
|
||||
const bool isOutput = nativeStream.getDirection() == oboe::Direction::Output;
|
||||
const int64_t appFrameIndex = isOutput ? nativeStream.getFramesWritten() : nativeStream.getFramesRead();
|
||||
|
||||
int64_t nextPresentationTimeNanos = lastFramePresentationTimeNanos + timeDeltaNanos;
|
||||
int64_t nextFrameWriteTimeNanos = getCurrentTimeNanos();
|
||||
// Assume that the next frame will be processed at the current time
|
||||
using namespace std::chrono;
|
||||
int64_t appFrameAppTime = getCurrentTimeNanos();//duration_cast<nanoseconds> (steady_clock::now().time_since_epoch()).count();
|
||||
int64_t appFrameAppTime2 = duration_cast<nanoseconds> (steady_clock::now().time_since_epoch()).count();
|
||||
|
||||
if (nextFrameWriteTimeNanos < 0)
|
||||
return;
|
||||
// Calculate the number of frames between app and hardware
|
||||
int64_t frameIndexDelta = appFrameIndex - hardwareFrameIndex;
|
||||
|
||||
outputLatency = (int) ((nextPresentationTimeNanos - nextFrameWriteTimeNanos) * sampleRate / oboe::kNanosPerSecond);
|
||||
// Calculate the time which the next frame will be or was presented
|
||||
int64_t frameTimeDelta = (frameIndexDelta * oboe::kNanosPerSecond) / sampleRate;
|
||||
int64_t appFrameHardwareTime = hardwareFrameHardwareTime + frameTimeDelta;
|
||||
|
||||
// Calculate latency as a difference in time between when the current frame is at the app
|
||||
// and when it is at the hardware.
|
||||
auto latencyNanos = isOutput ? (appFrameHardwareTime - appFrameAppTime) : (appFrameAppTime - appFrameHardwareTime);
|
||||
return static_cast<int> ((latencyNanos * sampleRate) / oboe::kNanosPerSecond);
|
||||
}
|
||||
|
||||
int64_t getCurrentTimeNanos()
|
||||
|
|
@ -900,19 +907,23 @@ private:
|
|||
|
||||
void onErrorBeforeClose (oboe::AudioStream* stream, oboe::Result error) override
|
||||
{
|
||||
attachAndroidJNI();
|
||||
|
||||
// only output stream should be the master stream receiving callbacks
|
||||
jassert (stream->getDirection() == oboe::Direction::Output);
|
||||
|
||||
JUCE_OBOE_LOG ("Oboe stream onErrorBeforeClose(): " + String (oboe::convertToText (error)));
|
||||
JUCE_OBOE_LOG ("Oboe stream onErrorBeforeClose(): " + getOboeString (error));
|
||||
printStreamDebugInfo (stream);
|
||||
}
|
||||
|
||||
void onErrorAfterClose (oboe::AudioStream* stream, oboe::Result error) override
|
||||
{
|
||||
attachAndroidJNI();
|
||||
|
||||
// only output stream should be the master stream receiving callbacks
|
||||
jassert (stream->getDirection() == oboe::Direction::Output);
|
||||
|
||||
JUCE_OBOE_LOG ("Oboe stream onErrorAfterClose(): " + String (oboe::convertToText (error)));
|
||||
JUCE_OBOE_LOG ("Oboe stream onErrorAfterClose(): " + getOboeString (error));
|
||||
|
||||
if (error == oboe::Result::ErrorDisconnected)
|
||||
{
|
||||
|
|
@ -948,7 +959,10 @@ private:
|
|||
Atomic<int> audioCallbackGuard { 0 },
|
||||
streamRestartGuard { 0 };
|
||||
|
||||
bool isOutputLatencyDetectionSupported = true;
|
||||
bool isInputLatencyDetectionSupported = false;
|
||||
int inputLatency = -1;
|
||||
|
||||
bool isOutputLatencyDetectionSupported = false;
|
||||
int outputLatency = -1;
|
||||
};
|
||||
|
||||
|
|
@ -1016,6 +1030,23 @@ private:
|
|||
return androidHasSystemFeature ("android.hardware.audio.pro");
|
||||
}
|
||||
|
||||
static int getDefaultFramesPerBurst()
|
||||
{
|
||||
// NB: this function only works for inbuilt speakers and headphones
|
||||
auto* env = getEnv();
|
||||
|
||||
auto audioManager = LocalRef<jobject> (env->CallObjectMethod (android.activity,
|
||||
JuceAppActivity.getSystemService,
|
||||
javaString ("audio").get()));
|
||||
|
||||
auto propertyJavaString = javaString ("android.media.property.OUTPUT_FRAMES_PER_BUFFER");
|
||||
|
||||
auto framesPerBurstString = LocalRef<jstring> ((jstring) android.activity.callObjectMethod (JuceAppActivity.audioManagerGetProperty,
|
||||
propertyJavaString.get()));
|
||||
|
||||
return framesPerBurstString != 0 ? env->CallStaticIntMethod (JavaInteger, JavaInteger.parseInt, framesPerBurstString.get(), 10) : 192;
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OboeAudioIODevice)
|
||||
};
|
||||
|
||||
|
|
@ -1098,7 +1129,7 @@ public:
|
|||
forInput ? oboe::Direction::Input : oboe::Direction::Output,
|
||||
oboe::SharingMode::Shared,
|
||||
forInput ? 1 : 2,
|
||||
getSdkVersion() >= 21 ? oboe::AudioFormat::Float : oboe::AudioFormat::I16,
|
||||
getSDKVersion() >= 21 ? oboe::AudioFormat::Float : oboe::AudioFormat::I16,
|
||||
(int) OboeAudioIODevice::getNativeSampleRate(),
|
||||
OboeAudioIODevice::getNativeBufferSize(),
|
||||
nullptr);
|
||||
|
|
@ -1117,18 +1148,17 @@ public:
|
|||
|
||||
int getIndexOfDevice (AudioIODevice* device, bool asInput) const override
|
||||
{
|
||||
if (device == nullptr)
|
||||
return -1;
|
||||
if (auto oboeDevice = static_cast<OboeAudioIODevice*> (device))
|
||||
{
|
||||
auto oboeDeviceId = asInput ? oboeDevice->inputDeviceId
|
||||
: oboeDevice->outputDeviceId;
|
||||
|
||||
auto* oboeDevice = static_cast<OboeAudioIODevice*> (device);
|
||||
auto oboeDeviceId = asInput ? oboeDevice->inputDeviceId
|
||||
: oboeDevice->outputDeviceId;
|
||||
auto& devices = asInput ? inputDevices : outputDevices;
|
||||
|
||||
auto& devices = asInput ? inputDevices : outputDevices;
|
||||
|
||||
for (int i = 0; i < devices.size(); ++i)
|
||||
if (devices.getReference (i).id == oboeDeviceId)
|
||||
return i;
|
||||
for (int i = 0; i < devices.size(); ++i)
|
||||
if (devices.getReference (i).id == oboeDeviceId)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -1233,11 +1263,11 @@ public:
|
|||
|
||||
bool supportsDevicesInfo() const
|
||||
{
|
||||
static auto result = getSdkVersion() >= 23;
|
||||
static auto result = getSDKVersion() >= 23;
|
||||
return result;
|
||||
}
|
||||
|
||||
int getSdkVersion() const
|
||||
int getSDKVersion() const
|
||||
{
|
||||
static auto sdkVersion = getEnv()->GetStaticIntField (AndroidBuildVersion, AndroidBuildVersion.SDK_INT);
|
||||
return sdkVersion;
|
||||
|
|
@ -1399,7 +1429,7 @@ public:
|
|||
return testStream != nullptr && testStream->openedOk();
|
||||
}
|
||||
|
||||
pthread_t startThread (void* (*entry) (void*), void* userPtr)
|
||||
pthread_t startThread (void*(*entry)(void*), void* userPtr)
|
||||
{
|
||||
pthread_mutex_lock (&threadReadyMutex);
|
||||
|
||||
|
|
@ -1439,26 +1469,16 @@ public:
|
|||
|
||||
void onErrorBeforeClose (oboe::AudioStream*, oboe::Result error) override
|
||||
{
|
||||
JUCE_OBOE_LOG ("OboeRealtimeThread: Oboe stream onErrorBeforeClose(): " + String (oboe::convertToText (error)));
|
||||
JUCE_OBOE_LOG ("OboeRealtimeThread: Oboe stream onErrorBeforeClose(): " + getOboeString (error));
|
||||
ignoreUnused (error);
|
||||
jassertfalse; // Should never get here!
|
||||
}
|
||||
|
||||
void onErrorAfterClose (oboe::AudioStream* stream, oboe::Result error) override
|
||||
void onErrorAfterClose (oboe::AudioStream*, oboe::Result error) override
|
||||
{
|
||||
JUCE_OBOE_LOG ("OboeRealtimeThread: Oboe stream onErrorAfterClose(): " + String (oboe::convertToText (error)));
|
||||
|
||||
if (error == oboe::Result::ErrorDisconnected)
|
||||
{
|
||||
testStream.reset();
|
||||
testStream.reset (new OboeStream (-1,
|
||||
oboe::Direction::Output,
|
||||
oboe::SharingMode::Exclusive,
|
||||
1,
|
||||
formatUsed,
|
||||
(int) OboeAudioIODevice::getNativeSampleRate(),
|
||||
OboeAudioIODevice::getNativeBufferSize(),
|
||||
this));
|
||||
testStream->start();
|
||||
}
|
||||
JUCE_OBOE_LOG ("OboeRealtimeThread: Oboe stream onErrorAfterClose(): " + getOboeString (error));
|
||||
ignoreUnused (error);
|
||||
jassertfalse; // Should never get here!
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -1482,10 +1502,7 @@ pthread_t juce_createRealtimeAudioThread (void* (*entry) (void*), void* userPtr)
|
|||
return {};
|
||||
|
||||
auto threadID = thread->startThread (entry, userPtr);
|
||||
|
||||
// the thread will de-allocate itself
|
||||
thread.release();
|
||||
|
||||
thread.release(); // the thread will de-allocate itself
|
||||
return threadID;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue