21#include <aaudio/AAudio.h>
56 if (loopThread_.joinable())
66 loopCv_.wait(
lk, [
this] {
return not isRunning_
or not streamsToRestart_.empty(); });
69 auto streams = std::move(streamsToRestart_);
71 JAMI_WARNING(
"Restarting stream type {} after disconnection", (
unsigned) stream);
72 stopStreamLocked(stream);
73 startStreamLocked(stream);
89AAudioLayer::AAudioStreamPtr
105 "AAudioStreamBuilder_setUsage"));
107 "AAudioStreamBuilder_setContentType"));
109 "AAudioStreamBuilder_setInputPreset"));
115 JAMI_WARNING(
"AAudioStreamBuilder_setUsage not available, stream usage will be unknown");
123 "AAudioStreamBuilder_setContentType not available, stream content type will be unknown");
129 JAMI_WARNING(
"AAudioStreamBuilder_setInputPreset not available, input preset will be unknown");
139 JAMI_ERROR(
"Error opening {} stream: {}. Retrying with shared.",
147 JAMI_ERROR(
"Error opening {} stream (shared): {}",
158 std::lock_guard lock(
mutex_);
159 startStreamLocked(stream);
165 JAMI_WARNING(
"Starting AAudio layer for stream type {}", (
unsigned) stream);
174 JAMI_ERROR(
"Failed to create playback stream");
188 JAMI_WARNING(
"Playback stream started with format: {}, buffer size: {} frames",
197 if (ringStream_ || javaRingTrack_)
207 if (!startJavaRingStream()) {
208 JAMI_ERROR(
"Failed to start Java ringtone stream fallback");
225 JAMI_WARNING(
"Ringtone stream started with format: {}, buffer size: {} frames",
245 JAMI_WARNING(
"Capture stream started with format: {}", format.toString());
254 loopThread_ = std::thread([
this] { loop(); });
261 std::lock_guard lock(
mutex_);
263 streamsToRestart_.clear();
265 streamsToRestart_.erase(stream);
267 stopStreamLocked(stream);
273 JAMI_WARNING(
"Stopping AAudio layer for stream type {}", (
unsigned) stream);
284 if (javaRingTrack_) {
285 stopJavaRingStream();
286 }
else if (ringStream_) {
327 JAMI_WARNING(
"Underrun detected (count: {}), increasing buffer size to {} frames",
337 const float*
src =
reinterpret_cast<const float*
>(
frame->pointer()->data[0]);
340 JAMI_WARNING(
"Playback underflow: no data available, filling with silence");
344 auto out = std::make_shared<AudioFrame>(format,
numFrames);
345 if (
out->pointer() &&
out->pointer()->data[0]) {
346 auto*
dst =
reinterpret_cast<float*
>(
out->pointer()->data[0]);
366 std::lock_guard
lk(
layer->mutex_);
368 layer->loopCv_.notify_one();
372std::vector<std::string>
395AAudioLayer::startJavaRingStream()
398 JAMI_ERROR(
"AAudioLayer: no JavaVM — cannot create Java ringtone AudioTrack");
403 bool attached =
false;
409 JAMI_ERROR(
"AAudioLayer: failed to attach thread for ringtone stream creation");
413 JAMI_ERROR(
"AAudioLayer: cannot obtain JNIEnv for ringtone stream creation");
419 JAMI_ERROR(
"AAudioLayer: AudioTrack class not found");
420 if (attached)
sJavaVM->DetachCurrentThread();
447 if (!
track ||
env->ExceptionCheck()) {
448 env->ExceptionClear();
449 JAMI_ERROR(
"AAudioLayer: failed to construct Java AudioTrack for ringtone");
451 if (attached)
sJavaVM->DetachCurrentThread();
458 JAMI_ERROR(
"AAudioLayer: Java AudioTrack not initialised (wrong state)");
461 if (attached)
sJavaVM->DetachCurrentThread();
471 javaRingTrack_ =
env->NewGlobalRef(
track);
477 if (attached)
sJavaVM->DetachCurrentThread();
483 javaRingRunning_ =
true;
484 javaRingThread_ = std::thread([
this] { javaRingLoop(); });
486 JAMI_WARNING(
"AAudioLayer: Java STREAM_RING AudioTrack started (API < 28 fallback)");
493AAudioLayer::javaRingLoop()
499 bool attached =
false;
505 JAMI_ERROR(
"AAudioLayer: ring thread failed to attach to JVM");
517 while (javaRingRunning_) {
520 const auto*
src =
reinterpret_cast<const float*
>(
frame->pointer()->data[0]);
522 env->CallIntMethod(javaRingTrack_,
530 std::this_thread::sleep_for(std::chrono::milliseconds(5));
535 sJavaVM->DetachCurrentThread();
539AAudioLayer::stopJavaRingStream()
541 javaRingRunning_ =
false;
542 if (javaRingThread_.joinable())
543 javaRingThread_.join();
545 if (!
sJavaVM || !javaRingTrack_)
549 bool attached =
false;
563 env->DeleteGlobalRef(javaRingTrack_);
564 env->DeleteGlobalRef(
reinterpret_cast<jobject>(javaRingBuffer_));
567 javaRingTrack_ =
nullptr;
568 javaRingBuffer_ =
nullptr;
571 sJavaVM->DetachCurrentThread();
574 JAMI_WARNING(
"AAudioLayer: Java STREAM_RING AudioTrack stopped");
577std::vector<std::string>
void updatePreference(AudioPreference &pref, int index, AudioDeviceType type) override
void startStream(AudioDeviceType stream) override
Start the capture stream and prepare the playback stream.
static void setJavaVM(JavaVM *vm)
AAudioLayer(const AudioPreference &pref)
std::string getAudioDeviceName(int index, AudioDeviceType type) const override
int getAudioDeviceIndex(const std::string &name, AudioDeviceType type) const override
std::vector< std::string > getPlaybackDeviceList() const override
std::vector< std::string > getCaptureDeviceList() const override
void stopStream(AudioDeviceType stream=AudioDeviceType::ALL) override
Stop the playback and capture streams.
std::mutex mutex_
Lock for the entire audio layer.
std::atomic< Status > status_
Whether or not the audio layer's playback stream is started.
void playbackChanged(bool started)
void setHasNativeNS(bool hasNS)
void hardwareFormatAvailable(AudioFormat playback, size_t bufSize=0)
Callback to be called by derived classes when the audio output is opened.
std::shared_ptr< AudioFrame > getToRing(AudioFormat format, size_t writableSamples)
void hardwareInputFormatAvailable(AudioFormat capture)
Set the input format on necessary objects.
void setHasNativeAEC(bool hasEAC)
void recordChanged(bool started)
#define JAMI_ERROR(formatstr,...)
#define JAMI_WARNING(formatstr,...)
void(*)(AAudioStreamBuilder *, aaudio_input_preset_t) SetInputPresetFunc
static constexpr int JAVA_STATE_INITIALIZED
static constexpr int JAVA_STREAM_RING
void(*)(AAudioStreamBuilder *, aaudio_usage_t) SetUsageFunc
void emitSignal(Args... args)
static constexpr int JAVA_RING_CHANNELS
static constexpr int JAVA_CHANNEL_OUT_STEREO
static constexpr int JAVA_RING_SAMPLE_RATE
static constexpr int JAVA_MODE_STREAM
static constexpr int JAVA_RING_FRAMES
static constexpr int JAVA_ENCODING_PCM_FLOAT
void(*)(AAudioStreamBuilder *, aaudio_content_type_t) SetContentTypeFunc
static constexpr int JAVA_RING_FLOATS
static constexpr int JAVA_WRITE_BLOCKING
AudioFormat getStreamFormat(AAudioStream *stream)