OSDN Git Service

[OSD][Qt][SOUND][QT_MULTIMEDIA][WIP] Separating sound driver to a module, this still...
authorK.Ohta <whatisthis.sowhat@gmail.com>
Mon, 25 Jul 2022 16:41:42 +0000 (01:41 +0900)
committerK.Ohta <whatisthis.sowhat@gmail.com>
Mon, 25 Jul 2022 16:41:42 +0000 (01:41 +0900)
source/src/qt/osd_sound_mod_qtmultimedia.cpp [new file with mode: 0644]
source/src/qt/osd_sound_mod_qtmultimedia.h [new file with mode: 0644]
source/src/qt/osd_sound_mod_template.h

diff --git a/source/src/qt/osd_sound_mod_qtmultimedia.cpp b/source/src/qt/osd_sound_mod_qtmultimedia.cpp
new file mode 100644 (file)
index 0000000..f2496bf
--- /dev/null
@@ -0,0 +1,326 @@
+
+#include "./osd_sound_mod_qtmultimedia.h"
+
+SOUND_OUTPUT_MODULE_QTMULTIMEDIA::SOUND_OUTPUT_MODULE_QTMULTIMEDIA(
+               OSD_BASE *parent,
+               USING_FLAGS *pflags,
+               CSP_Logger *logger,
+               int base_rate,
+               int base_latency_ms,
+               int base_channels,
+               void *extra_configvalues)
+               :
+       SOUND_OUTPUT_MODULE_QTMULTIMEDIA(
+               fileio_ptr, parent, pflags, logger,
+               base_rate, base_latency_ms, base_channels,
+               extra_configvalues)
+{
+       m_audioOutput = nullptr;
+       m_samples = 0;
+       reconfig_sound(base_rate, base_channels, base_latency_ms);
+}
+
+SOUND_OUTPUT_MODULE_QTMULTIMEDIA::~SOUND_OUTPUT_MODULE_QTMULTIMEDIA()
+{
+       release_sound();
+}
+
+bool SOUND_OUTPUT_MODULE_QTMULTIMEDIA::real_reconfig_sound(int& rate,int& channels,int& latency_ms)
+{
+       if((rate <= 0) || (channels < 1) || (latency_ms < 10)) {
+               return false;
+       }
+       m_samples = (rate * latency_ms) / 1000;
+       initialize_sound(rate, m_samples, &m_rate, &m_samples);
+       if((m_rate <= 0) || (m_samples <= 0)) {
+               return false;
+       }
+       return m_config_ok;
+}
+
+void SOUND_OUTPUT_MODULE_QTMULTIMEDIA::initialize_sound(int rate, int samples, int* presented_rate, int* presented_samples)
+{
+       QAudioFormat desired;
+       if(m_audioOutputSink != nullptr) {
+               m_audioOutputSink->stop();
+               delete m_audioOutputSink;
+               m_audioOutputSink = nullptr;
+               sound_us_before_rendered = 0;
+       }
+#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
+       desired.setChannelCount(m_channels);
+       desired.setSampleRate(m_rate);
+       desired.setSampleFormat(QAudioFormat::Int16);
+       // ToDo
+       desired.setChannelConfig(QAudioFormat::ChannelConfigStereo);
+#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+       desired.setChannelCount(m_channels);
+       desired.setSampleRate(m_rate);
+       desired.setSampleSize(16);
+       desired.setSampleType(QAudioFormat::SignedInt);
+       #if Q_BYTE_ORDER == Q_BIG_ENDIAN        
+       desired.setByteOrder(QAudioFormat::BigEndian);
+       #else
+       desired.setByteOrder(QAudioFormat::LittleEndian);
+       #endif  
+#endif
+//     if(!(m_audioOutputDevice.isFormatSupported(desired))) {
+//             desired = m_audioOutputDevice.preferredFormat();
+//     }
+       m_audioOutputFormat = desired;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
+       m_audioOutputSink = new QAudioSink(m_audioOutputDevice, m_audioOutputFormat, this);
+#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+       m_audioOutputSink = new QAudioOutput(m_audioOutputDevice, m_audioOutputFormat, this);
+#endif
+       if(samples <= 0) return;
+
+       rate = m_audioOutputFormat.sampleRate();
+       //int channels = m_audioOutputFormat.sampleRate();
+       if(rate <= 0) rate = 8000;
+       
+       sound_us_before_rendered = 0;
+       
+       if(m_audioOutput != nullptr)
+       {
+               m_config_ok =  m_audioOutput->resize(samples * channels * sizeof(int16_t) * 4);
+       } else {
+               m_audioOutput = new SOUND_BUFFER_QT(samples * channels * sizeof(int16_t) * 4);
+               m_config_ok =  (m_audioOutput != nullptr);
+       }
+       if(!(m_config_ok)) return;
+       
+       m_samples = samples;
+
+       if(m_audioOutput->isOpen()) {
+               m_audioOutput->close();
+       }
+       if(m_audioOutput != nullptr) {
+       #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+               m_audioOutput->open(QIODeviceBase::ReadWrite | QIODeviceBase::Truncate | QIODeviceBase::Unbuffered);
+       #else
+               m_audioOutput->open(QIODevice::ReadWrite | QIODevice::Truncate | QIODevice::Unbuffered);
+       #endif
+               m_audioOutput->reset();
+               if(m_audioOutputSink != nullptr) {
+                       #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+                       m_audioOutputSink->start(m_audioOutput);
+                       #endif
+                       sound_us_before_rendered = 0;
+               }
+       }
+       
+       m_samples = samples;
+       m_rate = rate;
+       
+       debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND,"Sample rate=%d samples=%d\n", m_rate, m_samples);
+
+       sound_ok = sound_started = now_mute = false;
+       if(presented_rate != nullptr) {
+               *presented_rate = m_rate;
+       }
+       if(presented_samples != nullptr) {
+               *presented_samples = m_samples;
+       }
+       
+       if(m_audioOutputSink != nullptr) {
+               sound_ok = true;
+               sound_initialized = true;
+               if(p_config != nullptr) {
+                       double _ll = (double)(p_config->general_sound_level + INT16_MAX) / 65535.0;
+                       m_audioOutputSink->setVolume(_ll);
+               }
+               connect(m_audioOutputSink, SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleAudioOutputStateChanged(QAudio::State)));
+       } else {
+               sound_ok = false;
+               sound_initialized = false;
+               m_audioOutput = nullptr;
+               sound_us_before_rendered = 0;
+       }
+       if(sound_ok) {
+               connect(this, SIGNAL(sig_sound_start()),  this, SLOT(do_sound_start()), Qt::QueuedConnection);
+               connect(this, SIGNAL(sig_sound_resume()),  m_audioOutputSink, SLOT(resume()), Qt::QueuedConnection);
+               connect(this, SIGNAL(sig_sound_suspend()), m_audioOutputSink, SLOT(suspend()), Qt::QueuedConnection);
+               connect(this, SIGNAL(sig_sound_stop()),    m_audioOutputSink, SLOT(stop()), Qt::QueuedConnection);
+               
+       }
+       
+//     debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND,
+//                                               "Sound OK: BufSize = %d", outbuffer_length);
+
+
+}
+
+
+void SOUND_OUTPUT_MODULE_QTMULTIMEDIA::release_sound()
+{
+       std::lock_guard<std::recursive_mutex> locker(m_locker);
+       sound_exit = true;
+       sound_ok = false;
+       sound_initialized = false;
+       if(m_audioOutputSink != nullptr) {
+               delete m_audioOutputSink;
+               m_audioOutputSink = nullptr;
+       }
+       if(m_audioOutput != nullptr) {
+               if(m_audioOutput->isOpen()) {
+                       m_audioOutput->close();
+               }
+               delete m_audioOutput;
+               m_audioOutput = nullptr;
+       }
+}
+
+void SOUND_OUTPUT_MODULE_QTMULTIMEDIA::do_sound_start()
+{
+       if(m_audioOutput != nullptr) {
+               m_audioOutput->reset();
+               if(m_audioOutputSink != nullptr) {
+                       m_audioOutputSink->start(m_audioOutput);
+               }
+       }
+}
+
+
+void OSD_BASE::update_sound(int* extra_frames)
+{
+       *extra_frames = 0;
+       
+       now_mute = false;
+       if(sound_ok) {
+               //debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND, "Sink->bytesFree() = %d", m_audioOutputSink->bytesFree());
+               
+               const int64_t sound_us_now = (int64_t)m_audioOutputSink->elapsedUSecs();
+               const int64_t  _period_usec = (((int64_t)sound_samples * (int64_t)10000) / (int64_t)sound_rate) * 100;
+               int64_t _diff = sound_us_now - (int64_t)sound_us_before_rendered;
+               if((_diff < 0) && ((INT64_MAX - (int64_t)sound_us_before_rendered + 1) <= _period_usec)) {
+                       // For uS overflow
+                       _diff = sound_us_now + (INT64_MAX - (int64_t)sound_us_before_rendered + 1);
+               }
+               //debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND, "update_sound(): _diff=%lld _period_usec=%lld", _diff, _period_usec);
+               int now_mixed_ptr = 0;
+               if(m_OSD != nullptr) {
+                       VM_TEMPLATE* p_vm = m_OSD->get_vm();
+                       if(vm != nullptr) {
+                               now_mixed_ptr = vm->get_sound_buffer_ptr();
+                       }
+               }
+               if(now_mixed_ptr < ((m_samples * 90) / 100)) {
+                       // Render even emulate 95% of latency when remain seconds is less than 2m Sec.
+                       return;
+               }
+               if((sound_started) && (_diff < (_period_usec - 1000))) {
+                       return;
+               }
+               qint64 left = 0;
+               qint64 buffer_len = m_samples * m_channels * sizeof(int16_t) * 4;
+               if(m_audioOutput != nullptr) {
+                       left = _size - m_audioOutput->bytesAvailable();
+               }
+               if(left < (sound_samples * 2 * sizeof(int16_t))) {
+                       return;
+               }                  
+               // Input
+               int16_t* sound_buffer = (int16_t*)create_sound(extra_frames);           
+               if(sound_buffer != nullptr) {
+                       if(!(sound_started)) {
+                               m_audioOutput->reset();
+               #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+                               m_audioOutputSink->start(m_audioOutput);
+               #else
+                               emit sig_sound_start();
+               #endif
+
+                       }
+                       sound_started = true;
+               }
+               if(now_record_sound || now_record_video) {
+                       if(sound_samples > rec_sound_buffer_ptr) {
+                               int samples = sound_samples - rec_sound_buffer_ptr;
+                               int length = samples * sizeof(int16_t) * 2; // stereo
+                               rec_sound_bytes += length;
+                               if(now_record_video) {
+                                       //AGAR_DebugLog(AGAR_LOG_DEBUG, "Push Sound %d bytes\n", length);
+                                       emit sig_enqueue_audio((int16_t *)(&(sound_buffer[rec_sound_buffer_ptr * 2])), length);
+                               }
+                               // record sound
+                               if(now_record_sound) {
+                                       rec_sound_fio->Fwrite(sound_buffer + rec_sound_buffer_ptr * 2, length, 1);
+                               }
+                               //if(now_record_video) {
+                               //      // sync video recording
+                               //      static double frames = 0;
+                               //      static int prev_samples = -1;
+                               //      static double prev_fps = -1;
+                               //      double fps = this->vm_frame_rate();
+                               //      frames = fps * (double)samples / (double)sound_rate;
+                               //}
+                               //printf("Wrote %d samples ptr=%d\n", samples, rec_sound_buffer_ptr);
+                               rec_sound_buffer_ptr += samples;
+                               if(rec_sound_buffer_ptr >= sound_samples) rec_sound_buffer_ptr = 0;
+                       }
+               }
+               //if(sound_initialized) return;
+               if(sound_buffer != nullptr) {
+                       if((m_audioOutput != nullptr) /*&& (m_audioOutputSink != nullptr)*/) {
+                               // ToDo: Not Int16.
+                               //qint64 sound_len = sound_samples * sound_rate * 2 * wordsize;
+                               qint64 sound_len = m_samples * m_channels * sizeof(int16_t);
+
+                               qint64 written = 0;
+                               if(m_using_flags != nullptr) {
+                                       config_t* p_config = m_using_flags->get_config_ptr();
+                                       if(p_config != nullptr) {
+                                               double _ll = (double)(p_config->general_sound_level + INT16_MAX) / 65535.0;
+                                               m_audioOutputSink->setVolume(_ll);
+                                       }
+                               }
+                               qint64 _result = m_audioOutput->write((const char *)sound_buffer, sound_len);
+                               sound_us_before_rendered = m_audioOutputSink->elapsedUSecs();
+                       }
+               }
+       }
+}
+
+void OSD_BASE::mute_sound()
+{
+       if(!(now_mute) && (sound_ok)) {
+               if(m_audioOutputSink != nullptr) {
+                       switch(m_audioOutputSink->state()) {
+                       case QAudio::ActiveState:
+                       case QAudio::IdleState:
+                               emit sig_sound_suspend();
+                               break;
+                       default:
+                               break;
+                       }
+                       if(m_audioOutput != nullptr) {
+                               m_audioOutput->reset();
+                       }
+                       
+               }
+       }
+       now_mute = true;
+}
+
+void OSD_BASE::stop_sound()
+{
+       if((sound_ok) && (sound_started)) {
+               if(m_audioOutputSink != nullptr) {
+                       switch(m_audioOutputSink->state()) {
+                       case QAudio::ActiveState:
+                       case QAudio::IdleState:
+                       case QAudio::SuspendedState:
+                               emit sig_stop_sound();
+                               break;
+                       default:
+                               break;
+                       }
+                       if(m_audioOutput != nullptr) {
+                               m_audioOutput->reset();
+                       }
+               }
+       }
+}
+
+
diff --git a/source/src/qt/osd_sound_mod_qtmultimedia.h b/source/src/qt/osd_sound_mod_qtmultimedia.h
new file mode 100644 (file)
index 0000000..a1a2e8c
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+       Skelton for retropc emulator
+
+       Author : K.Ohta <whatisthis.sowhat _at_ gmail.com>
+       Date   : 2022.07.25-
+
+       [ OSD / Sound driver / St Multimedia ]
+*/
+
+#pragma once
+
+#include "./osd_sound_mod_template.h"
+
+#include <QAudioFormat>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
+#include <QAudioDevice>
+#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+#include <QAudioDeviceInfo>
+#endif 
+
+QT_BEGIN_NAMESPACE
+
+class DLL_PREFIX SOUND_OUTPUT_MODULE_QTMULTIMEDIA
+       : public SOUND_OUTPUT_MODULE_BASE
+{
+       Q_OBJECT
+protected:
+       QAudioFormat m_audioOutputFormat;
+       std::shared_ptr<SOUND_BUFFER_QT> m_audioOutput;
+       qint64       m_samples;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
+       QAudioSink   *m_audioOutputSink;
+       QAudioDevice m_audioOutputDevice;
+#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+       QAudioOutput *m_audioOutputSink;
+
+       QAudioDeviceInfo m_audioOutputDevice;
+#endif 
+       
+public:
+       SOUND_OUTPUT_MODULE_QTMULTIMEDIA(
+               OSD_BASE *parent,
+               USING_FLAGS *pflags,
+               CSP_Logger *logger,
+               int base_rate = 48000,
+               int base_latency_ms = 100,
+               int base_channels = 2,
+               void *extra_configvalues = nullptr);
+
+       ~SOUND_OUTPUT_MODULE_QTMULTIMEDIA();
+
+       virtual bool real_reconfig_sound(int& rate,int& channels,int& latency_ms) override;
+       
+public slots:
+       virtual bool set_fileio(std::shared_ptr<SOUND_BUFFER_QT> fileio_ptr) override;
+       virtual void initialize_sound(int rate, int samples, int* presented_rate, int* presented_samples) override;
+       virtual void release_sound() override;
+
+       virtual void update_sound(int* extra_frames) override;
+       virtual void mute_sound() override;
+       virtual void stop_sound() override;
+
+       virtual int result_opening_external_file() override;
+       virtual int64_t wrote_data_to() override;
+       virtual bool result_closing_external_file() override;
+       
+};
index 430a445..9f495a8 100644 (file)
 
 #include <QObject>
 #include <mutex>
+#include <memory>
 
 #include "../common.h"
-#include "../fifo_templates.h"
+#include "./sound_buffer_qt.h"
 
 QT_BEGIN_NAMESPACE
 
@@ -21,201 +22,125 @@ class OSD_BASE;
 class USING_FLAGS;
 class CSP_Logger;
 
-class DLL_PREFIX SOUND_MODULE_BASE : public QObject
+class DLL_PREFIX SOUND_OUTPUT_MODULE_BASE : public QObject
 {
        Q_OBJECT
 protected:
        OSD_BASE    *m_OSD;
        USING_FLAGS *m_using_flags;
        CSP_Logger  *m_logger;
-       void        *m_extconfig;
-       FIFO_BASE::LOCKED_RINGBUFFER<int16_t> *m_queue;
-       std::recursive_mutex m_locker;
-       std::recursive_mutex m_locker_outqueue;
+
+       std::atomic_bool     m_config_ok;
+       std::atomic<void *>  m_extconfig;
+       int     m_rate;
+       int m_channels;
+       int     m_latency_ms;
+       std::recursive_mutex             m_locker;
+       std::atomic_int m_loglevel;
+       std::atomic_int m_logdomain;
 public:
-       SOUND_MODULE_BASE(OSD_BASE *parent, USING_FLAGS *pflags, CSP_Logger *logger, int buffer_size = 4096, void *configvalues = nullptr)
-               : m_OSD(parent), m_using_flags(pflags), m_logger(logger),
-               m_extconfig(configvalues), 
-               QObject(qobject_cast<QObject*>parent)
-       {
-               m_queue = new FIFO_BASE::LOCKED_RINGBUFFER<int16_t>(buffer_size);
-       }
-       ~SOUND_MODULE_BASE()
-       {
-               std::lock_guard<std::recursive_mutex> locker(m_locker);
-               std::lock_guard<std::recursive_mutex> locker(m_locker_outqueue);
-               if(m_queue != nullptr) {
-                       delete m_queue;
-               }
-       }
-       virtual int get_sound_rate(bool is_input = false, int dev_channel = 0)
-       {
-               return 44100;
-       }
-       
-       virtual int64_t enqueueOutputSink(int16_t* p, int64_t size)
-       {
-               std::lock_guard<std::recursive_mutex> locker(m_locker_outqueue);
-               if(m_queue != nullptr) {
-                       bool flag;
-                       int64_t wsize = m_queue->write(p, size, flag);
-                       if((wsize > size) || (wsize <= 0) || !(flag)) {
-                               return 0;
-                       }
-                       return wsize;
-               }
-               return 0;
-       }
-       
-       virtual int64_t dequeueOutputSink(int16_t* p, int64_t size)
-       {
-               std::lock_guard<std::recursive_mutex> locker(m_locker_outqueue);
-               if(m_queue != nullptr) {
-                       bool flag;
-                       int64_t rsize = m_queue->read(p, size, flag);
-                       if((rsize > size) || (rsize <= 0) || !(flag)) {
-                               return 0;
-                       }
-                       return rsize;
-               }
-               return 0;
-       }
-       virtual int64_t enqueueInputSource(int device_ch, int16_t* p, int64_t size)
-       {
-               return 0;
-       }
-       virtual int64_t dequeueInputSource(int device_ch, int16_t* p, int64_t size)
-       {
-               return 0;
-       }
-       
-       virtual int64_t outputSinkQueueSize()
-       {
-               std::lock_guard<std::recursive_mutex> locker(m_locker_outqueue);
-               if(m_queue != nullptr) {
-                       return m_queue->size();
-               }
-               return 0;
-       }
-       virtual int64_t outputSinkDataCount()
-       {
-               std::lock_guard<std::recursive_mutex> locker(m_locker_outqueue);
-               if(m_queue != nullptr) {
-                       return m_queue->count();
-               }
-               return 0;
-       }
-       virtual bool outputSinkQueueAvailable()
-       {
-               std::lock_guard<std::recursive_mutex> locker(m_locker_outqueue);
-               if(m_queue != nullptr) {
-                       return m_queue->available();
-               }
-               return false;
-       }
-       virtual bool outputSinkQueueReadReady()
-       {
-               std::lock_guard<std::recursive_mutex> locker(m_locker_outqueue);
-               if(m_queue != nullptr) {
-                       return m_queue->read_ready();
+       SOUND_OUTPUT_MODULE_BASE(
+               OSD_BASE *parent,
+               USING_FLAGS *pflags,
+               CSP_Logger *logger,
+               int base_rate = 48000,
+               int base_latency_ms = 100,
+               int base_channels = 2,
+               void *extra_configvalues = nullptr)
+               : m_OSD(parent), 
+               m_using_flags(pflags),
+               m_logger(logger),
+               QObject(qobject_cast<QObject*>parent),
+       {
+               if(m_logger != nullptr) {
+                       QObject::connect(this, SIGNAL(sig_send_log(int, int, QString)),
+                                                        m_logger, SLOT(do_debug_log(int, int, QString)),
+                                                        Qt::QueueedConnection);
                }
-               return false;
-       }
-       virtual bool outputSinkQueueWriteReady()
-       {
-               std::lock_guard<std::recursive_mutex> locker(m_locker_outqueue);
-               if(m_queue != nullptr) {
-                       return m_queue->write_ready();
-               }
-               return false;
-       }
-
-
-       virtual int64_t inputSourceQueueSize(int input_ch = 0)
-       {
-               return 0;
-       }
-       virtual int64_t inputSourceDataCount(int input_ch = 0)
-       {
-               return 0;
+               m_rate = base_rate;
+               m_latency_ms = base_latency_ms;
+               m_channels = base_channels;
+               m_extconfig = configvalues;
+               m_config_ok = real_reconfig_sound(m_rate, m_channels, m_latency_ms);
+               m_loglevel = CSP_LOG_INFO;
+               m_logdomain = CSP_LOG_TYPE_SOUND;
        }
-       virtual bool inputSourceQueueAvailable(int input_ch = 0)
+       ~SOUND_OUTPUT_MODULE_BASE()
        {
-               return false;
-       }
-       virtual bool inputSourceQueueReadReady(int input_ch = 0)
-       {
-               return false;
-       }
-       virtual bool inputSourceQueueWriteReady(int input_ch = 0)
-       {
-               return false;
        }
        
-       virtual bool initalizeSoundOutputDevice(int channels, int sample_rate, int& samples_per_chunk, int& chunks, std::string device_name)
-       {
-               return true;
-       }
-
-       virtual bool initalizeSoundOutputDevice(int channels, int sample_rate, int& samples_per_chunk, int& chunks, int device_num)
+       int get_sound_rate()
        {
-               return true;
+               std::lock_guard<std::recursive_mutex> locker(m_locker);
+               return m_rate;
        }
-       virtual bool detachSoundOutputDevice()
+       int get_latency()
        {
-               return true;
+               std::lock_guard<std::recursive_mutex> locker(m_locker);
+               return m_latency_ms;
        }
-       virtual bool isSoundOutputDeviceReady()
+       int get_channels()
        {
-               return false;
+               std::lock_guard<std::recursive_mutex> locker(m_locker);
+               return m_channels;
        }
-
-       virtual bool initalizeSoundInputDevice(int channels, int sample_rate, int& samples_per_chunk, int& chunks, std::string device_name)
-       {
+       virtual bool real_reconfig_sound(int& rate,int& channels,int& latency_ms) {
                return true;
-       }
-
-       virtual bool initalizeSoundInputDevice(int input_channel, int channels, int sample_rate, int& samples_per_chunk, int& chunks, int device_num)
-       {
+       }       
+       template <class... Args>
+               bool debug_log(Args... args)
+       {
+               _TCHAR buf[512] = {0};
+               my_sprintf_s(buf, sizeof(buf) - 1, args); 
+               QString s = QString::fromUtf8(buf);
+               emit sig_send_log(m_loglevel, m_logdomain, s);
                return true;
        }
-       virtual void detachSoundInputDevice(int input_channel = 0)
+       template <class... Args>
+               bool debug_log(imt level, int domain, Args... args)
        {
+               _TCHAR buf[512] = {0};
+               my_sprintf_s(buf, sizeof(buf) - 1, args); 
+               QString s = QString::fromUtf8(buf);
+               emit sig_send_log(level, domain, s);
                return true;
        }
-       virtual bool isSoundInputDeviceReady(int input_channel = 0)
-       {
-               return false;
-       }
-       
-       virtual void soundOutHandler(int64_t& req_size, void* userdata = nullptr)
+       bool config_ok()
        {
+               return m_config_ok.load();
        }
-       virtual void soundInHandler(int64_t &req_size, void* userdata = nullptr)
+public slot:
+       bool update_rate(int& rate)
        {
+               return reconfig_sound(rate, m_channels, m_latency_ms);
        }
-       // Kick sound out handler
-       virtual bool soundOutReq()
+       bool update_latency(int& latency_ms)
        {
-               return true;
+               return reconfig_sound(m_rate, m_channels, latency_ms);
        }
-       // Kick sound in handler
-       virtual bool soundInReq(int input_ch)
+       bool update_channels(int& channels)
        {
-               return true;
+               return reconfig_sound(rate, m_channels, m_latency_ms);
        }
-public slot:
-       virtual void initialize_sound(int rate, int samples, int* presented_rate, int* presented_samples)
+       bool reconfig_sound(int& rate, int& channels, int& latency_ms)
        {
-               std::lock_guard<std::recursive_mutex> locker(m_locker_outqueue);
-               // more lock via m_locker etc, if needs.
-               if(presented_rate != nullptr) {
-                       *presenyted_rate = rate;
-               }
-               if(presented_samples != nullptr) {
-                       *presenyted_samples = samples;
+               // ToDo
+               std::lock_guard<std::recursive_mutex> locker(m_locker);
+               if((rate != m_rate) || (channels != m_channels) || (latency_ms != m_latency_ms)) {
+                       if(real_reconfig_sound(rate, channels, latency_ms)) {
+                               m_rate = rate;
+                               m_channels = channels;
+                               m_latency_ms = latency_ms;
+                               m_config_ok = true;
+                               return true;
+                       }
                }
+               return false;
        }
+
+       virtual void initialize_sound(int rate, int samples, int* presented_rate, int* presented_samples) {}
+       virtual void release_sound() {}
+
        virtual void update_sound(int* extra_frames) {}
        virtual void mute_sound() {}
        virtual void stop_sound() {}
@@ -225,14 +150,20 @@ public slot:
        virtual void do_stop_recording_sound() {}
        virtual void do_restart_recording_sound() {}
        virtual void do_request_capture_sound(int ch) {}
-       virtual void do_resize_output_buffer(int count, int channels) {}
-       virtual void do_resize_capture_buffer(int ch, int count, int channels) {}
-       virtual void do_receive_external_sound(int count, int channels, int16_t* data) {}
-
+       
        virtual void set_logger(CSP_Logger* logger)
        {
                std::lock_guard<std::recursive_mutex> locker(m_locker);
+               if(m_logger != nullptr) {
+                       QObject::disconnect(this, SIGNAL(sig_send_log(int, int, QString)),
+                                                               m_logger, SLOT(do_debug_log(int, int, QString)));
+               }
                m_logger = logger;
+               if(m_logger != nullptr) {
+                       QObject::connect(this, SIGNAL(sig_send_log(int, int, QString)),
+                                                        m_logger, SLOT(do_debug_log(int, int, QString)),
+                                                        Qt::QueueedConnection);
+               }
        }
        virtual void set_osd(OSD_BASE* p)
        {
@@ -251,13 +182,26 @@ public slot:
                m_extconfig = p;
                // more lock via m_locker_outqueue etc, if needs.
        }
-       
+       virtual int result_opening_external_file()
+       {
+               return 0;
+       }
+       virtual int64_t wrote_data_to()
+       {
+               return 0;
+       }
+       virtual bool result_closing_external_file()
+       {
+               return true;
+       }
 signals:
-       void sig_send_log(QString);
-       void sig_send_log_with_class(int, int, QString);
-       void sig_req_input(int64_t);
-       void sig_complete_output(int64_t);
-       void sig_send_captured_sound_data(int, int64_t, int, int16_t[]);
+       // loglevel, logdomain, message
+       void sig_send_log(int, int, QString);
+       // rate, channels, path
+       void sig_req_open_sound(int, int, QString);
+       // 
+       void sig_req_close_sound();
+       // samples, channel, data
        void sig_send_output_sound_data(int64_t, int, int16_t[]);
 };