From c116a7b4369c264fc33ba2c0d48350d16537e0ae Mon Sep 17 00:00:00 2001
From: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
Date: Thu, 22 Oct 2020 11:05:19 -0400
Subject: [PATCH] coreaudio: use queue to start/stop audio

This patch add a queue to start/stop audio so it would
not block execution thread.

Change-Id: I4ca454a98395e71f00de38c511d18886d8ffbf1a
---
 src/media/audio/coreaudio/Makefile.am         |  3 +-
 src/media/audio/coreaudio/ios/corelayer.h     |  2 +-
 src/media/audio/coreaudio/ios/corelayer.mm    | 72 ++++++++++---------
 src/media/audio/coreaudio/osx/corelayer.h     |  3 -
 .../osx/{corelayer.cpp => corelayer.mm}       | 49 +++++++------
 5 files changed, 67 insertions(+), 62 deletions(-)
 rename src/media/audio/coreaudio/osx/{corelayer.cpp => corelayer.mm} (95%)

diff --git a/src/media/audio/coreaudio/Makefile.am b/src/media/audio/coreaudio/Makefile.am
index 10d07d47ea..655f144bb8 100644
--- a/src/media/audio/coreaudio/Makefile.am
+++ b/src/media/audio/coreaudio/Makefile.am
@@ -2,7 +2,7 @@ include $(top_srcdir)/globals.mk
 
 if HAVE_OSX
 noinst_LTLIBRARIES = libcoreaudiolayer.la
-libcoreaudiolayer_la_SOURCES = osx/corelayer.cpp osx/corelayer.h osx/audiodevice.cpp osx/audiodevice.h
+libcoreaudiolayer_la_SOURCES = osx/corelayer.mm osx/corelayer.h osx/audiodevice.cpp osx/audiodevice.h
 endif
 
 if HAVE_IOS
@@ -11,3 +11,4 @@ libcoreaudiolayer_la_SOURCES = ios/corelayer.mm ios/corelayer.h
 endif
 
 libcoreaudiolayer_la_CXXFLAGS = -I$(top_srcdir)/src
+AM_OBJCXXFLAGS = -std=c++17
diff --git a/src/media/audio/coreaudio/ios/corelayer.h b/src/media/audio/coreaudio/ios/corelayer.h
index 1155f94261..b1dbfb87ca 100644
--- a/src/media/audio/coreaudio/ios/corelayer.h
+++ b/src/media/audio/coreaudio/ios/corelayer.h
@@ -23,7 +23,6 @@
 #define CORE_LAYER_H_
 
 #include "audio/audiolayer.h"
-#include "noncopyable.h"
 #include <AudioToolbox/AudioToolbox.h>
 
 #define checkErr(err) \
@@ -162,6 +161,7 @@ private:
     UInt32 outChannelsPerFrame_;
 
     std::condition_variable readyCv_ {};
+    dispatch_queue_t audioConfigurationQueue;
 };
 
 } // namespace jami
diff --git a/src/media/audio/coreaudio/ios/corelayer.mm b/src/media/audio/coreaudio/ios/corelayer.mm
index 54640bc66d..5552e783ce 100644
--- a/src/media/audio/coreaudio/ios/corelayer.mm
+++ b/src/media/audio/coreaudio/ios/corelayer.mm
@@ -21,20 +21,20 @@
 
 #include "corelayer.h"
 #include "manager.h"
-#include "noncopyable.h"
-#include "audio/ringbufferpool.h"
-#include "audio/ringbuffer.h"
-#include "libav_utils.h"
-
 #include <AVFoundation/AVAudioSession.h>
 
-#include <cmath>
-#include <vector>
-
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
 
 namespace jami {
+dispatch_queue_t audioConfigurationQueueIOS() {
+    static dispatch_once_t queueCreationGuard;
+    static dispatch_queue_t queue;
+    dispatch_once(&queueCreationGuard, ^{
+        queue = dispatch_queue_create("audioConfigurationQueueIOS", DISPATCH_QUEUE_SERIAL);
+    });
+    return queue;
+}
 
 // AudioLayer implementation.
 CoreLayer::CoreLayer(const AudioPreference &pref)
@@ -43,11 +43,19 @@ CoreLayer::CoreLayer(const AudioPreference &pref)
     , indexOut_(pref.getAlsaCardout())
     , indexRing_(pref.getAlsaCardring())
     , playbackBuff_(0, audioFormat_)
-{}
+{
+     audioConfigurationQueue = dispatch_queue_create("com.savoirfairelinux.audioConfigurationQueueIOS", DISPATCH_QUEUE_SERIAL);
+}
 
 CoreLayer::~CoreLayer()
 {
-    stopStream();
+    dispatch_sync(audioConfigurationQueueIOS(), ^{
+        if (status_ != Status::Started)
+            return;
+        destroyAudioLayer();
+        flushUrgent();
+        flushMain();
+    });
 }
 
 std::vector<std::string>
@@ -317,29 +325,25 @@ CoreLayer::bindCallbacks() {
 void
 CoreLayer::startStream(AudioDeviceType stream)
 {
-    std::lock_guard<std::mutex> lock(mutex_);
-    JAMI_DBG("iOS CoreLayer - Start Stream");
-    auto currentCategoty =  [[AVAudioSession sharedInstance] category];
+    dispatch_async(audioConfigurationQueueIOS(), ^{
+        JAMI_DBG("iOS CoreLayer - Start Stream");
+        auto currentCategoty =  [[AVAudioSession sharedInstance] category];
+
+        bool updateStream = currentCategoty == AVAudioSessionCategoryPlayback && (stream == AudioDeviceType::CAPTURE || stream == AudioDeviceType::ALL);
+        if (status_ == Status::Started) {
+            if (updateStream)
+                destroyAudioLayer();
+            else
+                return;
+        }
+        status_ = Status::Started;
 
-    bool updateStream = currentCategoty == AVAudioSessionCategoryPlayback && (stream == AudioDeviceType::CAPTURE || stream == AudioDeviceType::ALL);
-    if (status_ == Status::Started) {
-        if (updateStream)
+        dcblocker_.reset();
+        if (!initAudioLayerIO(stream) || AudioUnitInitialize(ioUnit_) || AudioOutputUnitStart(ioUnit_)) {
             destroyAudioLayer();
-        else
-            return;
-    }
-    status_ = Status::Started;
-
-    dcblocker_.reset();
-    if (initAudioLayerIO(stream)) {
-        auto inputRes = AudioUnitInitialize(ioUnit_);
-        auto outputRes = AudioOutputUnitStart(ioUnit_);
-        if (!inputRes && !outputRes) {
-            return;
+            status_ = Status::Idle;
         }
-    }
-    destroyAudioLayer();
-    status_ = Status::Idle;
+    });
 }
 
 void
@@ -354,15 +358,13 @@ CoreLayer::destroyAudioLayer()
 void
 CoreLayer::stopStream(AudioDeviceType stream)
 {
-    JAMI_DBG("iOS CoreLayer - Stop Stream");
-    {
-        std::lock_guard<std::mutex> lock(mutex_);
+    dispatch_async(audioConfigurationQueueIOS(), ^{
+        JAMI_DBG("iOS CoreLayer - Stop Stream");
         if (status_ != Status::Started)
             return;
         status_ = Status::Idle;
         destroyAudioLayer();
-    }
-
+    });
     /* Flush the ring buffers */
     flushUrgent();
     flushMain();
diff --git a/src/media/audio/coreaudio/osx/corelayer.h b/src/media/audio/coreaudio/osx/corelayer.h
index 8409a49f1d..1428447524 100644
--- a/src/media/audio/coreaudio/osx/corelayer.h
+++ b/src/media/audio/coreaudio/osx/corelayer.h
@@ -22,10 +22,7 @@
 #define CORE_LAYER_H_
 
 #include "audio/audiolayer.h"
-#include "noncopyable.h"
-#include <CoreFoundation/CoreFoundation.h>
 #include <AudioToolbox/AudioToolbox.h>
-#include <CoreAudio/AudioHardware.h>
 
 #define checkErr(err) \
     if (err) { \
diff --git a/src/media/audio/coreaudio/osx/corelayer.cpp b/src/media/audio/coreaudio/osx/corelayer.mm
similarity index 95%
rename from src/media/audio/coreaudio/osx/corelayer.cpp
rename to src/media/audio/coreaudio/osx/corelayer.mm
index 823f516ec0..d6eb58a884 100644
--- a/src/media/audio/coreaudio/osx/corelayer.cpp
+++ b/src/media/audio/coreaudio/osx/corelayer.mm
@@ -20,17 +20,19 @@
 
 #include "corelayer.h"
 #include "manager.h"
-#include "noncopyable.h"
-#include "audio/resampler.h"
-#include "audio/ringbufferpool.h"
-#include "audio/ringbuffer.h"
 #include "audiodevice.h"
 
-#include <cmath>
-#include <vector>
-
 namespace jami {
 
+dispatch_queue_t audioConfigurationQueueMacOS() {
+    static dispatch_once_t queueCreationGuard;
+    static dispatch_queue_t queue;
+    dispatch_once(&queueCreationGuard, ^{
+        queue = dispatch_queue_create("audioConfigurationQueueMacOS", DISPATCH_QUEUE_SERIAL);
+    });
+    return queue;
+}
+
 // AudioLayer implementation.
 CoreLayer::CoreLayer(const AudioPreference& pref)
     : AudioLayer(pref)
@@ -42,7 +44,13 @@ CoreLayer::CoreLayer(const AudioPreference& pref)
 
 CoreLayer::~CoreLayer()
 {
-    stopStream();
+    dispatch_sync(audioConfigurationQueueMacOS(), ^{
+        if (status_ != Status::Started)
+            return;
+        destroyAudioLayer();
+        flushUrgent();
+        flushMain();
+    });
 }
 
 std::vector<std::string>
@@ -294,10 +302,9 @@ CoreLayer::initAudioLayerIO(AudioDeviceType stream)
 void
 CoreLayer::startStream(AudioDeviceType stream)
 {
-    JAMI_DBG("START STREAM");
+    dispatch_async(audioConfigurationQueueMacOS(), ^{
+        JAMI_DBG("START STREAM");
 
-    {
-        std::lock_guard<std::mutex> lock(mutex_);
         if (status_ != Status::Idle)
             return;
         status_ = Status::Started;
@@ -306,13 +313,13 @@ CoreLayer::startStream(AudioDeviceType stream)
 
         initAudioLayerIO(stream);
 
-        auto inputRes = AudioUnitInitialize(ioUnit_);
-        auto outputRes = AudioOutputUnitStart(ioUnit_);
-        if (!inputRes && !outputRes) {
-            return;
+        auto inputError = AudioUnitInitialize(ioUnit_);
+        auto outputError = AudioOutputUnitStart(ioUnit_);
+        if (inputError || outputError) {
+            status_ = Status::Idle;
+            destroyAudioLayer();
         }
-    }
-    stopStream();
+    });
 }
 
 void
@@ -326,15 +333,13 @@ CoreLayer::destroyAudioLayer()
 void
 CoreLayer::stopStream(AudioDeviceType stream)
 {
-    JAMI_DBG("STOP STREAM");
-    {
-        std::lock_guard<std::mutex> lock(mutex_);
+    dispatch_async(audioConfigurationQueueMacOS(), ^{
+        JAMI_DBG("STOP STREAM");
         if (status_ != Status::Started)
             return;
         status_ = Status::Idle;
         destroyAudioLayer();
-    }
-
+    });
     /* Flush the ring buffers */
     flushUrgent();
     flushMain();
-- 
GitLab