OSDN Git Service

[OSD][SOUND][Qt][WIP] Implementing sound driver skelton.This still be work-in-progress.
authorK.Ohta <whatisthis.sowhat@gmail.com>
Tue, 16 Aug 2022 18:08:29 +0000 (03:08 +0900)
committerK.Ohta <whatisthis.sowhat@gmail.com>
Tue, 16 Aug 2022 18:08:29 +0000 (03:08 +0900)
source/src/qt/osd_base.h
source/src/qt/osd_sound.cpp
source/src/qt/osd_sound_mod_template.cpp
source/src/qt/osd_sound_mod_template.h

index 3eb9f00..7640312 100644 (file)
@@ -695,10 +695,8 @@ public:
        void debug_log(int level, int domain_num, char *strbuf);
        virtual double get_vm_current_usec() { return 0.0; }
        virtual uint64_t get_vm_current_clock_uint64() { return 0;}
-       
 
        std::shared_ptr<USING_FLAGS> get_config_flags(void) { return using_flags; }
-
        // Special
        std::shared_ptr<CSP_Logger> get_logger(void) { return p_logger; }
        virtual bool set_glview(GLDrawClass *glv) { /* Dummy */ return false;}
index a356f9b..fcd0fc7 100644 (file)
@@ -450,6 +450,37 @@ void OSD_BASE::release_sound()
 #include <QtMultimedia>
 void OSD_BASE::initialize_sound(int rate, int samples, int* presented_rate, int* presented_samples)
 {
+#if 0
+       std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver;
+       disconnect(this, SIGNAL(sig_set_volume(double)), nullptr, nullptr);
+       disconnect(this, SIGNAL(sig_snd_reset_to_default()), nullptr, nullptr);
+       
+       if(out_driver.get() != nullptr) {
+               int latency_ms = (samples * 1000) / rate;
+               if(out_driver->reconfig_sound(rate, 2)) { // ToDo: Channels.
+                       out_driver->update_latency(latency_ms, true);
+                       rate = out_driver->get_sample_rate();
+                       latency_ms = out_driver->get_latency_ms();
+                       samples = (latency_ms * 1000) / rate;
+               }
+               sound_us_before_rendered = out_driver->driver_processed_usec();
+               elapsed_us_before_rendered = out_driver->driver_elapsed_usec();
+               
+               connect(this, SIGNAL(sig_snd_set_volume(double)), out_driver->get_real_driver(), SLOT(set_volume(double)));
+               connect(this, SIGNAL(sig_snd_reset_to_default()), out_driver->get_real_driver(), SLOT(reset_to_default()));
+               
+               connect(this, SIGNAL(sig_snd_request_to_release()), out_driver.get(), SLOT(request_to_release()));
+               
+               //connect(this, SIGNAL(sig_snd_update_rate(int)), out_driver.get(), SLOT(update_rate(int)), Qt::QueuedConnection);
+               //connect(this, SIGNAL(sig_snd_update_channels(int)), out_driver.get(), SLOT(update_channels(int)), Qt::QueuedConnection);
+               //connect(this, SIGNAL(sig_snd_update_latency(int)), out_driver.get(), SLOT(update_latency(int)), Qt::QueuedConnection);
+               //connect(this, SIGNAL(sig_snd_update_latency(int, bool)), out_driver.get(), SLOT(update_latency(int, bool)), Qt::QueuedConnection);
+               //connect(this, SIGNAL(sig_snd_reconfig(int, int)), out_driver.get(), SLOT(reconfig_sound(int, int)), Qt::QueuedConnection);
+       } else {
+               sound_us_before_rendered = 0;
+               elapsed_us_before_rendered = 0;
+       }
+#else  
        // ToDo: Sound Input
        QAudioFormat desired;
        
@@ -525,7 +556,7 @@ void OSD_BASE::initialize_sound(int rate, int samples, int* presented_rate, int*
                                  m_audioOutputDevice.deviceName().toLocal8Bit().constData());
        #endif
        }
-       
+#endif 
        sound_samples = samples;
        sound_rate = rate;
        
@@ -550,11 +581,21 @@ void OSD_BASE::initialize_sound(int rate, int samples, int* presented_rate, int*
        }
        
        sound_ok = true;
+       #if 0
+       if(out_driver.get() != nullptr) {
+               double _ll = 1.0;       
+               if(p_config != nullptr) {
+                       _ll = (double)(p_config->general_sound_level + INT16_MAX) / 65535.0;
+               }
+               emit sig_set_volume(_ll);
+       }
+       #else
        if(p_config != nullptr) {
                double _ll = (double)(p_config->general_sound_level + INT16_MAX) / 65535.0;
                m_audioOutputSink->setVolume(_ll);
        }
        connect(m_audioOutputSink.get(), SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleAudioOutputStateChanged(QAudio::State)));
+       #endif
        sound_initialized = true;
        debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND,
                                                  "Sound OK: BufSize = %d", outbuffer_length);
@@ -566,7 +607,11 @@ void OSD_BASE::release_sound()
        // release Qt Multimedia sound
        sound_exit = true;
        sound_initialized = false;
-       
+#if 0
+       m_output_driver->stop();
+       m_output_driver->reset_to_default();
+       disconnect(this, nullptr, m_output_driver.get(), nullptr);
+#else  
        m_audioOutputSink->stop();
        m_audioOutputSink->disconnect();
 
@@ -589,7 +634,7 @@ void OSD_BASE::release_sound()
                delete m_audioOutput;
                m_audioOutput = nullptr;
        }
-
+#endif
        sound_ok = false;
        sound_initialized = false;
 }
@@ -597,15 +642,29 @@ void OSD_BASE::release_sound()
 void OSD_BASE::do_update_master_volume(int level)
 {
        //std::lock_guard<std::recursive_timed_mutex> l(vm_mutex);
-
        double _ll = (double)(level + INT16_MAX) / 65535.0;
+#if 0
+       static const QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_set_volume(double)));
+       if(isSignalConnected(_sig)) {
+               emit sig_set_volume(_ll);
+       }
+#else
        m_audioOutputSink->setVolume(_ll);
+#endif
 }
 
 
 void OSD_BASE::do_set_host_sound_output_device(QString device_name)
 {
        if(device_name.isEmpty()) return;
+#if 0
+       static const QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_set_device(QString)));
+       if(isSignalConnected(_sig)) {
+               emit sig_set_device(device_name);
+               debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND,
+                                 "Set Audio Device to %s", device_name.toLocal8Bit().constData());
+       }
+#eise
        #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
        QString _older;
        _older = m_audioOutputDevice.description();
@@ -660,10 +719,18 @@ void OSD_BASE::do_set_host_sound_output_device(QString device_name)
                        sound_samples = dummy_samples;
                }
        }
+#endif
 }
 
 const _TCHAR *OSD_BASE::get_sound_device_name(int num)
 {
+#if 0
+       std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver;
+       if(out_driver.get() != nullptr) {
+               return out_driver->get_sound_device_name(num);
+       }
+       return (const _TCHAR*)nullptr;
+#else
        if((num < 0) || (num >= sound_device_list.count())) return (const _TCHAR *)nullptr;
 
        QString sdev = sound_device_list.at(num);
@@ -671,14 +738,22 @@ const _TCHAR *OSD_BASE::get_sound_device_name(int num)
        static QByteArray _n;
        _n.clear();
        _n = sdev.toUtf8().constData();
-
        return (const _TCHAR*)(_n.constData());
+#endif
 }
 
 void OSD_BASE::get_sound_device_list()
 {
-       sound_device_list.clear();
-#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
+#if 0
+       std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver;
+       if(out_driver.get() != nullptr) {
+               sound_device_list = out_driver->get_sound_devices_list();
+       } else {
+               sound_device_list.clear();
+       }
+#else
+       sound_device_list.clear();      
+       #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
        QList<QAudioDevice> tmplist = QMediaDevices::audioOutputs();
        int i = 0;
        for(auto p = tmplist.begin(); p != tmplist.end(); ++p) {
@@ -688,7 +763,7 @@ void OSD_BASE::get_sound_device_list()
                                  "Audio Device #%d: %s", i, tmps.toLocal8Bit().constData());
                i++;
        }
-#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+       #elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
        QList<QAudioDeviceInfo> tmplist = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);
        int i = 0;
        for(auto p = tmplist.begin(); p != tmplist.end(); ++p) {
@@ -698,6 +773,7 @@ void OSD_BASE::get_sound_device_list()
                                  "Audio Device #%d: %s", i, tmps.toLocal8Bit().constData());
                i++;
        }
+       #endif
 #endif
 }
                
@@ -1214,19 +1290,35 @@ void OSD_BASE::handleAudioOutputStateChanged(QAudio::State newState)
 }
 void OSD_BASE::update_sound(int* extra_frames)
 {
-       *extra_frames = 0;
-
-       #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
-       std::shared_ptr<QAudioSink>sink_ptr = m_audioOutputSink;
+       if(extra_frames != nullptr) {
+               *extra_frames = 0;
+       }
+       #if 0
+       std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver;
        #else
+               #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
+       std::shared_ptr<QAudioSink>sink_ptr = m_audioOutputSink;
+               #else
        std::shared_ptr<QAudioOutput>sink_ptr = m_audioOutputSink;
-       #endif  
+               #endif
+       #endif
        now_mute = false;
        if(sound_ok) {
+       #if 0
+               int64_t elapsed_us_now = 0;
+               int64_t sound_us_now = 0;
+               int64_t _period_usec = 100 * 1000;
+               if(out_driver.get() != nullptr) {
+                       elapsed_us_now = out_driver->driver_elapsed_usec();
+                       sound_us_now = out_driver->driver_processed_usec();
+                       _period_usec = out_driver->get_latency_ms() * 1000;
+               }
+       #else
                //debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND, "Sink->bytesFree() = %d", m_audioOutputSink->bytesFree());        
                const int64_t elapsed_us_now = (int64_t)(sink_ptr->elapsedUSecs());
                const int64_t sound_us_now = (int64_t)(sink_ptr->processedUSecs());
                const int64_t  _period_usec = (((int64_t)sound_samples * (int64_t)10000) / (int64_t)sound_rate) * 100;
+       #endif
                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
@@ -1238,22 +1330,16 @@ void OSD_BASE::update_sound(int* extra_frames)
                        _diff2 = elapsed_us_now + (INT64_MAX - (int64_t)elapsed_us_before_rendered + 1);
                }
 
-               int now_mixed_ptr = 0;
-               if(vm != nullptr) {
-                       now_mixed_ptr = vm->get_sound_buffer_ptr();
-               }
                if((sound_started) && (_diff2 < (_period_usec - 2000))) { // 2mSec
                        return;
                }  
-//             if((sound_started) && (_diff2 < (_period_usec - 5000))) { // 5mSec
-//                     if((sound_started) && (_diff < (_period_usec - 0))) { // 2mSec
-//                             return;
-//                     }
-//             }  
-//             if(now_mixed_ptr < ((sound_samples * 100) / 100)) {
-                       // Render even emulate 100% of latency when remain seconds is less than 2m Sec.
-//                     return;
-//             }
+       #if 0
+               if(out_driver.get() != nullptr) {
+                       if(out_driver->get_bytes_left() < out_driver->get_chunk_bytes()) {
+                               return;
+                       }
+               }
+       #else
                qint64 left = 0;
                qint64 _size = sound_samples * 2 * sizeof(int16_t) * 4;
                if(m_audioOutput != nullptr) {
@@ -1262,11 +1348,27 @@ void OSD_BASE::update_sound(int* extra_frames)
                if(left < (sound_samples * 2 * sizeof(int16_t))) {
                        return;
                }
+       #endif
 
                // Input
                int16_t* sound_buffer = (int16_t*)create_sound(extra_frames);
                
                if(sound_buffer != nullptr) {
+       #if 0
+                       if(out_driver.get() != nullptr) {
+                               if(!(sound_started)) {
+                                       out_driver->start();
+                                       elapse_us_before_rendered = out_driver->driver_elapsed_usec();
+                                       sound_us_before_rendered = out_driver->driver_processed_usec();
+                               } else {
+                                       if(_diff2 > (_period_usec * 2)) {
+                                               out_driver->discard();
+                                               elapse_us_before_rendered = out_driver->driver_elapsed_usec();
+                                               sound_us_before_rendered = out_driver->driver_processed_usec();
+                                       }
+                               }
+                       }
+       #else
                        if(!(sound_started)) {
                                m_audioOutput->reset();
                #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
@@ -1293,6 +1395,7 @@ void OSD_BASE::update_sound(int* extra_frames)
                #endif                                  
                                }
                        }
+       #endif
                        sound_started = true;
                }
                if(now_record_sound || now_record_video) {
@@ -1323,6 +1426,16 @@ void OSD_BASE::update_sound(int* extra_frames)
                }
                //if(sound_initialized) return;
                if(sound_buffer != nullptr) {
+       #if 0
+                       if(out_driver.get() != nullptr) {
+                               out_driver->update_sound((void *)sound_buffer, -1);
+                               elapse_us_before_rendered = out_driver->driver_elapsed_usec();
+                               sound_us_before_rendered = out_driver->driver_processed_usec();
+                       } else {
+                               elapse_us_before_rendered = 0;
+                               sound_us_before_rendered = 0;
+                       }
+       #else
                        if((m_audioOutput != nullptr) /*&& (m_audioOutputSink != nullptr)*/) {
                                // ToDo: Not Int16.
                                //qint64 sound_len = sound_samples * sound_rate * 2 * wordsize;
@@ -1335,11 +1448,29 @@ void OSD_BASE::update_sound(int* extra_frames)
                                elapsed_us_before_rendered = sink_ptr->elapsedUSecs();
                        }
                }
+       #endif
        }
 }
 
 void OSD_BASE::mute_sound()
 {
+#if 0
+       if(!(now_mute) && (sound_ok)) {
+               std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver;
+               if(out_driver.get() != nullptr) {
+                       int64_t _samples = out_driver->get_buffer_bytes();
+                       uint8_t* p = new uint8_t[_samples];
+                       out_driver->discard();
+                       if(p != nullptr) {
+                               memset(p, 0x00, _samples);
+                               out_driver->update_sound((void *)p, _samples);
+                               delete[] p;
+                       }
+                       sound_us_before_rendered = out_driver->driver_processed_usec();
+                       elapsed_us_before_rendered = out_driver->driver_elapsed_usec();
+               }
+       }
+#else
        if(!(now_mute) && (sound_ok)) {
        #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
                std::shared_ptr<QAudioSink>sink_ptr = m_audioOutputSink;
@@ -1359,10 +1490,21 @@ void OSD_BASE::mute_sound()
                sound_us_before_rendered = sink_ptr->processedUSecs();
                elapsed_us_before_rendered = sink_ptr->elapsedUSecs();
        }
+#endif
        now_mute = true;
 }
 void OSD_BASE::stop_sound()
 {
+#if 0
+       if((sound_ok) && (sound_started)) {
+               std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver;
+               if(out_driver.get() != nullptr) {
+                       out_driver->stop();
+               }
+               sound_us_before_rendered = 0;
+               elapsed_us_before_rendered = 0;
+       }
+#else
        if((sound_ok) && (sound_started)) {
        #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0)
                std::shared_ptr<QAudioSink>sink_ptr = m_audioOutputSink;
@@ -1385,6 +1527,7 @@ void OSD_BASE::stop_sound()
                        m_audioOutput->reset();
                }
        }
+#endif
 }
 
 #endif
@@ -1467,7 +1610,15 @@ int OSD_BASE::get_sound_rate()
 #else
 int OSD_BASE::get_sound_rate()
 {
+#if 0
+       std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver;
+       if(out_driver.get() != nullptr) {
+               return out_driver->get_sample_rate();
+       }
+       return 48000;
+#else
        return (int)(m_audioOutputFormat.sampleRate());
+#endif
 }
 #endif
 
index 125e598..8fd5727 100644 (file)
@@ -2,39 +2,43 @@
 
 
 SOUND_OUTPUT_MODULE_BASE::SOUND_OUTPUT_MODULE_BASE(OSD_BASE *parent,
-                                                                                                  _TCHAR* device_name,
+                                                                                                  SOUND_BUFFER_QT* deviceIO,
                                                                                                   int base_rate,
                                                                                                   int base_latency_ms,
                                                                                                   int base_channels,
                                                                                                   void *extra_config_values)
-       : m_OSD(parent),
+       : 
          m_config_ok(false),
          m_rate(base_rate),
          m_latency_ms(base_latency_ms),
          m_channels(base_channels),
          m_extconfig(extra_config_values),
+         m_wordsize(sizeof(int16_t)),
          QObject(qobject_cast<QObject*>parent)
 {
        m_device.clear();
-       if(m_OSD != nullptr) {
-               m_logger = m_OSD->get_logger();
-               m_using_flags = m_OSD->get_config_flags();
-       }
-       if(m_logger.get() != nullptr) {
-               QObject::connect(this, SIGNAL(sig_send_log(int, int, QString)),
-                                                m_logger.get(), SLOT(do_debug_log(int, int, QString)),
-                                                Qt::QueueedConnection);
+
+       m_logger.reset();
+       m_using_flags.reset();
+       set_osd(parent);
+
+       if(deviceIO != nullptr) {
+               m_fileio.reset(deviceIO);
+               m_buffer_bytes = deviceIO->size(); 
+               m_chunk_bytes =  m_buffer_bytes / 4;
+       } else {
+               if(m_channels < 1) m_channels = 1;
+               if(m_rate < 1000) m_rate = 1000;
+               m_chunk_bytes = ((qint64)(m_channels * m_wordsize * latency_ms) * (quint64)m_rate) / 1000;
+               m_buffer_bytes = m_chunk_bytes * 4;
+               m_fileio.reset(new SOUND_BUFFER_QT(m_buffer_bytes, this));
        }
+       
        m_loglevel = CSP_LOG_INFO;
        m_logdomain = CSP_LOG_TYPE_SOUND;
+       m_device_name.clear();
        
-       if(device_name == nullptr) {
-               m_device_name = std::string(_T("Default"));
-       } else {
-               QString tmpname = QString::fromUtf8(device_name);
-               m_device_name = tmpname.toStdString();
-       }
-       m_config_ok = false;
+       initialize_driver();
 }
 
 SOUND_OUTPUT_MODULE_BASE::~SOUND_OUTPUT_MODULE_BASE()
@@ -42,9 +46,12 @@ SOUND_OUTPUT_MODULE_BASE::~SOUND_OUTPUT_MODULE_BASE()
        if(m_config_ok.load()) {
                release_driver();
        }
+       m_fileio.reset();
+       
        m_config_ok = false;
 }
 
+
 void SOUND_OUTPUT_MODULE_BASE::request_to_release()
 {
        if(m_config_ok.load()) {
@@ -53,45 +60,367 @@ void SOUND_OUTPUT_MODULE_BASE::request_to_release()
        emit sig_released(!(m_config_ok.load()));
 }
 
-bool SOUND_OUTPUT_MODULE_BASE::do_send_log(int level, int domain, const _TCHAR* str, int maxlen)
+std::shared_ptr<QIODevice> SOUND_OUTPUT_MODULE_BASE::set_io_device(QIODevice *p)
 {
-       __UNLIKELY_IF((str == nullptr) || (maxlen <= 0)) return false;
-       __UNLIKELY_IF(strlen(str) <= 0) return false;
-       QString s = QString::fromUtf8(buf);
-       emit sig_send_log(level, domain, s);
-       return true;
+       
+       bool _f = is_running_sound();
+       if(m_fileio.get() != nullptr) {
+               _f &= m_fileio->isOpen();
+       }
+       stop();
+       if(p == nullptr) {
+               m_fileio.reset(new SOUND_BUFFER_QT(m_chunk_bytes * 4, this));
+       } else {
+               m_fileio.reset(p);
+       }
+       update_driver_fileio();
+       if(_f) {
+               start();
+       }
+       return m_fileio;
+}
+
+std::shared_ptr<QIODevice> SOUND_OUTPUT_MODULE_BASE::set_io_device(std::shared_ptr<QIODevice> ps)
+{
+       bool _f = is_running_sound();
+       if(m_fileio.get() != nullptr) {
+               _f &= m_fileio->isOpen();
+       }
+       stop();
+       m_fileio = ps;
+       update_driver_fileio();
+       if(_f) {
+               start();
+       }
+       return m_fileio;
+}
+
+
+bool SOUND_OUTPUT_MODULE_BASE::update_latency(int latency_ms, bool force)
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       if(latency_ms <= 0) {
+               return false;
+       }
+       if(!(force) && (m_latency_ms == latency_ms)) return true;
+       
+       m_latency_ms = latency_ms;
+       m_chunk_bytes = ((qint64)(m_channels * ((int)m_wordsize) * latency_ms) * (quint64)m_rate) / 1000;
+       m_buffer_bytes = m_chunk_bytes * 4;
+       
+       stop();
+       
+       std::shared_ptr<SOUND_BUFFER_QT> q = m_fileio;
+       if(q.get() != nullptr) {
+               q->reset();
+               if(!(q->resize(m_buffer_bytes))) {
+                       q->reset();
+                       m_buffer_bytes = (int64_t)(q->size());
+               }
+       } else {
+               m_fileio.reset(new SOUND_BUFFER_QT(m_buffer_bytes, this));
+       }
+       update_driver_fileio();
+       return (start() && (m_fileio.get() != nullptr));
+}
+
+
+bool SOUND_OUTPUT_MODULE_BASE::reconfig_sound(int rate, int channels)
+{
+       // ToDo
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       if((rate != m_rate) || (channels != m_channels)) {
+               if(real_reconfig_sound(rate, channels)) {
+                       m_rate = rate;
+                       m_channels = channels;
+                       m_config_ok = update_latency(m_latency_ms, true);
+                       return m_config_ok.load();
+               }
+       }
+       return false;
+}
+
+int64_t SOUND_OUTPUT_MODULE_BASE::update_sound(void* datasrc, int samples)
+{
+       std::shared_ptr<SOUND_BUFFER_QT>q = m_fileio;   
+
+       if(q.get() == nullptr) return -1;
+       
+       if(samples > 0) {
+               qint64 _size = (qint64)(samples * m_channels) * (qint64)m_wordsize;
+               return (int64_t)q->write((const char *)datasrc, _size);
+       } else if(samples < 0) {
+               return (int64_t)q->write((const char *)datasrc, m_chunk_bytes);
+       }
+       return -1;
+}
+
+bool SOUND_OUTPUT_MODULE_BASE::start()
+{
+       std::shared_ptr<SOUND_BUFFER_QT>q = m_fileio;
+       if(is_running_sound()) { // ToDo: STOP
+               stop();
+       }
+       bool _stat = false;
+       
+       if(q.get() != nullptr) {
+               _stat = q->open(QIODeviceBase::Write | QIODeviceBase::Unbuffered);
+               update_driver_fileio();
+       }       
+       if(_stat) {
+               QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_start_audio()));
+               if(isSignalConnected(_sig)) {
+                       emit sig_start_audio();
+               }
+       }
+       return _stat;
+}
+
+bool SOUND_OUTPUT_MODULE_BASE::pause()
+{
+       QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_pause_audio()));
+       if(isSignalConnected(_sig)) {
+               emit sig_pause_audio();
+               return true;
+       }
+       return false;
+}
+
+bool SOUND_OUTPUT_MODULE_BASE::resume()
+{
+       QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_resume_audio()));
+       if(isSignalConnected(_sig)) {
+               emit sig_resume_audio();
+               return true;
+       }
+       return false;
+}
+
+bool SOUND_OUTPUT_MODULE_BASE::stop()
+{
+       bool _stat = false;
+       QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_close_audio()));
+       if(isSignalConnected(_sig)) {
+               emit sig_close_audio();
+               _stat = true;
+       }
+       std::shared_ptr<SOUND_BUFFER_QT>q = m_fileio;
+
+       if(q.get() != nullptr) {
+               if(q->isOpen()) {
+                       q->close();
+               }
+               return _stat;
+       }
+       return false;
+}
+
+bool SOUND_OUTPUT_MODULE_BASE::discard()
+{
+//     std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+//     std::shared_ptr<SOUND_BUFFER_QT> q = m_fileio;
+//     if(q.get() != nullptr) {
+               QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_discard_audio()));
+               if(isSignalConnected(_sig)) {
+                       emit sig_discard_audio();
+                       return true;
+               }
+//     }
+       return false;
 }
 
+void SOUND_OUTPUT_MODULE_BASE::do_set_device_by_name(void)
+{
+       QAction *cp = qobject_cast<QAction*>(QObject::sender());
+       if(cp == nullptr) return;
+       QString _id = cp->data().value<QString>();
+       do_set_device_by_name(_id);
+}
+
+void SOUND_OUTPUT_MODULE_BASE::do_set_device_by_number(void)
+{
+       QAction *cp = qobject_cast<QAction*>(QObject::sender());
+       if(cp == nullptr) return;
+       int _id = cp->data().value<int>();
+       do_set_device_by_number(_id);
+}
+
+
+bool SOUND_OUTPUT_MODULE_BASE::do_send_log(int level, int domain, const _TCHAR* _str, int maxlen)
+{
+       __UNLIKELY_IF((_str == nullptr) || (maxlen <= 0)) return false;
+       __UNLIKELY_IF(strlen(_str) <= 0) return false;
+       
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       __LIKELY_IF(isSignalConnected(SIGNAL(sig_send_log(int, int, const _TCHAR*, int)))) {
+               emit sig_send_log(level, domain, _str, maxlen);
+               return true;
+       }
+       
+       QString s = QString::fromUtf8(_str, maxlen);
+       
+       __LIKELY_IF(isSignalConnected(SIGNAL(sig_send_log(int, int, QString)))) {
+               emit sig_send_log(level, domain, s);
+               return true;
+       }
+       return false;
+}
+
+bool SOUND_OUTPUT_MODULE_BASE::do_send_log(int level, int domain, const QString _str)
+{
+       __UNLIKELY_IF(str.isEmpty()) return false;
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       
+       __LIKELY_IF(isSignalConnected(SIGNAL(sig_send_log(int, int, QString)))) {
+               emit sig_send_log(level, domain, _str);
+               return true;
+       }
+       return false;
+}
+
+
 void SOUND_OUTPUT_MODULE_BASE::set_logger(const std::shared_ptr<CSP_Logger> logger)
 {
-       std::lock_guard<std::recursive_mutex> locker(m_locker);
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
        if(m_logger.get() != nullptr) {
-               QObject::disconnect(this, SIGNAL(sig_send_log(int, int, QString)),
-                                                       m_logger.get(), SLOT(do_debug_log(int, int, QString)));
+               disconnect(this, nullptr, m_logger.get(), nullptr);
        }
        m_logger = logger;
        if(m_logger.get() != nullptr) {
-               QObject::connect(this, SIGNAL(sig_send_log(int, int, QString)),
-                                                m_logger.get(), SLOT(do_debug_log(int, int, QString)),
-                                                Qt::QueueedConnection);
+               connect(this, SIGNAL(sig_send_log(int, int, QString)),
+                               m_logger.get(), SLOT(do_send_log(int, int, QString)),
+                               Qt::QueuedConnection);
        }
 }
+
 void SOUND_OUTPUT_MODULE_BASE::set_osd(OSD_BASE* p)
 {
-       std::lock_guard<std::recursive_mutex> locker(m_locker);
-       m_OSD = p;
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       if(p != nullptr) {
+               m_OSD = p;
+               set_logger(p->get_logger());
+               set_system_flags(p->get_config_flags());
+       } else {
+               m_OSD = nullptr;
+               if(m_logger.get() != nullptr) {
+                       disconnect(this, nullptr, m_logger.get(), nullptr);
+               }
+               m_logger.reset();
+               m_using_flags.reset();
+       }
 }
 
 void SOUND_OUTPUT_MODULE_BASE::set_system_flags(const std::shared_ptr<USING_FLAGS> p)
 {
-       std::lock_guard<std::recursive_mutex> locker(m_locker);
        m_using_flags = p;
+       update_config();
+}
+
+bool SOUND_OUTPUT_MODULE_BASE::set_extra_config(void* p, int bytes)
+{
+       if((p == nullptr) || (bytes <= 0)) {
+               return false;
+       }
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       m_extconfig_ptr   = p;
+       m_extconfig_bytes = bytes;
+       update_extra_config();
+       return true;
 }
 
-void SOUND_OUTPUT_MODULE_BASE::update_extra_config(void* p)
+bool SOUND_OUTPUT_MODULE_BASE::modify_extra_config(void* p, int& bytes)
 {
-       std::lock_guard<std::recursive_mutex> locker(m_locker);
-       m_extconfig = p;
-       // more lock via m_locker_outqueue etc, if needs.
+       if((p == nullptr) || (bytes <= 0)) {
+               return false;
+       }
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       uint8_t* q = (uint8_t*)(m_extconfig_ptr.load());
+       if(q == nullptr) {
+               return false;
+       }
+       bytes = std::min(bytes, m_extconfig_bytes.load());
+       memcpy(q, p, bytes);
+       update_extra_config();
+       return true;
 }
 
+bool SOUND_OUTPUT_MODULE_BASE::is_io_device_exists()
+{
+       std::shared_ptr<QIODevice> p = m_fileio;
+       if(p.get() != nullptr) {
+               return true;
+       }
+       return false;
+}
+
+int64_t SOUND_OUTPUT_MODULE_BASE::get_buffer_bytes()
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       return m_buffer_bytes;
+}
+
+int64_t SOUND_OUTPUT_MODULE_BASE::get_chunk_bytes()
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       return m_chunk_bytes;
+}
+
+int SOUND_OUTPUT_MODULE_BASE::get_latency_ms()
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       return m_latency_ms;
+}
+       
+int SOUND_OUTPUT_MODULE_BASE::get_channels()
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       return m_channels;
+}
+
+int SOUND_OUTPUT_MODULE_BASE::get_sample_rate()
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       return m_rate;
+}
+
+size_t SOUND_OUTPUT_MODULE_BASE::get_word_size()
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       return m_wordsize;
+}
+
+void SOUND_OUTPUT_MODULE_BASE::get_buffer_parameters(int& channels, int& rate,
+                                                                                                        int& latency_ms, size_t& word_size,
+                                                                                                        int& chunk_bytes, int& buffer_bytes)
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       channels = m_channels;
+       rate = m_rate;
+       latency_ms = m_latency_ms;
+       word_size = m_wordsize;
+       chunk_bytes = m_chunk_bytes;
+       buffer_bytes = m_buffer_bytes;
+}
+
+int64_t SOUND_OUTPUT_MODULE_BASE::get_bytes_available()
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       std::shared_ptr<SOUND_BUFFER_QT> p = m_fileio;
+       if(p.get() != nullptr) {
+               return p->bytesAvailable();
+       }
+       return 0;
+}
+
+int64_t SOUND_OUTPUT_MODULE_BASE::get_bytes_left()
+{
+       std::lock_guard<std::recursive_timed_mutex> locker(m_locker);
+       std::shared_ptr<SOUND_BUFFER_QT> p = m_fileio;
+       
+       if(p.get() != nullptr) {
+               int64_t n = m_buffer_bytes - p->bytesAvailable();
+               if(n < 0) n = 0;
+               return n;
+       }
+       return 0;
+}
index 9dd3efd..b70e1f7 100644 (file)
@@ -26,169 +26,233 @@ class DLL_PREFIX SOUND_OUTPUT_MODULE_BASE : public QObject
 {
        Q_OBJECT
 protected:
-       OSD_BASE    *m_OSD;
-       std::shared_ptr<USING_FLAGS> m_using_flags;
-       std::shared_ptr<CSP_Logger>  m_logger;
-
-       std::atomic_bool    m_config_ok;
-       std::atomic<void *> m_extconfig;
-       std::atomic<int>        m_rate;
-       std::atomic<int>        m_channels;
-       std::atomic<int>        m_latency_ms;
-       std::recursive_mutex             m_locker;
-       std::atomic<int>        m_loglevel;
-       std::atomic<int>        m_logdomain;
-       std::string                     m_device_name;
-       
-       bool                            m_initialized;
+       OSD*                                                            m_OSD;
+       std::shared_ptr<SOUND_BUFFER_QT>        m_fileio;
+       std::shared_ptr<USING_FLAGS>            m_using_flags;
+       
+       std::atomic<bool>                                       m_config_ok;
+
+       int64_t                                                         m_chunk_bytes;
+       int64_t                                                         m_buffer_bytes;
+       
+       int                                                                     m_rate;
+       int                                                                     m_latency_ms;
+       int                                                                     m_channels;
+       size_t                                                          m_wordsize;
+       std::atomic<void*>                                      m_extconfig_ptr;
+       std::atomic<int>                                        m_extconfig_bytes;
+       std::atomic<int>                                        m_loglevel;
+       std::atomic<int>                                        m_logdomain;
+
+       virtual void update_driver_fileio()
+       {
+               release_driver_fileio();
+               // Update driver side of fileio by m_fileio;
+               //connect(m_fileio.get(), SIGNAL(bytesWritten(qint64)), real_driver, SLOT, QObject::DirectConnection);
+               //connect(m_fileio.get(), SIGNAL(aboutToClose()), real_driver, SLOT, QObject::DirectConnection);
+               // Optional:
+               // connect(m_fileio.get(), SIGNAL(readyRead()), real_driver, SLOT, QObject::DirectConnection);
+       }
+
+       virtual void release_driver_fileio()
+       {
+               // Maybe disconnect some signals via m_fileio.
+       }
+       
+       template <class... Args>
+               bool debug_log(Args... args)
+       {
+               _TCHAR buf[1024];
+               memset(buf, 0x00, sizeof(buf));
+               my_sprintf_s(buf, sizeof(buf) - 1, args);
+
+               return do_send_log(m_loglevel.load(), m_logdomain.load(),
+                                                  QString::fromUtf8(buf, sizeof(buf)));
+       }
        
 public:
-       SOUND_OUTPUT_MODULE_BASE(
-               OSD_BASE *parent,
-               _TCHAR* device_name,
-               const std::shared_ptr<CSP_Logger> logger,
-               const std::shared_ptr<USING_FLAGS> pflags,
-               int base_rate = 48000,
-               int base_latency_ms = 100,
-               int base_channels = 2,
-               void *extra_config_values = nullptr);
+       SOUND_OUTPUT_MODULE_BASE(OSD_BASE *parent,
+                                                        SOUND_BUFFER_QT* deviceIO = nullptr,
+                                                        int base_rate = 48000,
+                                                        int base_latency_ms = 100,
+                                                        int base_channels = 2,
+                                                        void *extra_config_values = nullptr);
        ~SOUND_OUTPUT_MODULE_BASE();
 
-       virtual bool initialize_driver() { return true; }
-       virtual bool release_driver() { return true; }
-       int get_sound_rate()
+       std::recursive_timed_mutex                              m_locker;
+
+       virtual void initialize_driver()
        {
-               return m_rate.load();
+               // AT LEAST:
+               // connect(this, SIGNAL(sig_start_audio()), ..., QObject::QueuedConnection);
+               // connect(this, SIGNAL(sig_pause_audio()), ..., QObject::QueuedConnection);
+               // connect(this, SIGNAL(sig_resume_audio()), ..., QObject::QueuedConnection);
+               // connect(this, SIGNAL(sig_close_audio()), ..., QObject::QueuedConnection);
+               // connect(this, SIGNAL(sig_discard_audio()), ..., QObject::QueuedConnection);
+               // connect(this, SIGNAL(sig_released(bool)), ..., QObject::QueuedConnection);
+               // connect(this, SIGNAL(sig_req_open_sound(int, int, QString)), ..., QObject::QueuedConnection);
+
+               // For Logging
+               // connect(real_driver, SIGNAL(sig_log(QString)), this, SLOT(do_send_log(QString)), QObject::QueuedConnection);
+               // connect(real_driver, SIGNAL(sig_log(int, int, QString)), this, SLOT(do_send_log(int, int, QString)), QObject::QueuedConnection);
        }
-       int get_latency()
+       virtual void release_driver()
        {
-               return m_latency_ms.load();
        }
-       int get_channels()
+       
+       int64_t update_sound(void* datasrc, int samples);
+       
+       std::shared_ptr<QIODevice> set_io_device(QIODevice *p);
+       std::shared_ptr<QIODevice> set_io_device(std::shared_ptr<QIODevice> ps);
+       std::shared_ptr<QIODevice> get_io_device()
        {
-               return m_channels.load();
+               return m_fileio;
        }
-       virtual bool real_reconfig_sound(int& rate,int& channels,int& latency_ms)
+       bool is_io_device_exists();
+       
+       virtual uint64_t wrote_data_to()
        {
-               return true;
+               return 0;
        }
-       template <class... Args>
-               bool debug_log(Args... args)
+       virtual int64_t driver_elapsed_usec()
        {
-               _TCHAR buf[512] = {0};
-               my_sprintf_s(buf, sizeof(buf) - 1, args);
-               return do_send_log(m_loglevel.load(), m_logdomain.load(), (const _TCHAR*)buf, (sizeof(buf) / sizeof(_TCHAR)) - 1);
+               return 0;
        }
-       template <class... Args>
-               bool debug_log(imt level, int domain, Args... args)
+       virtual int64_t driver_processed_usec()
        {
-               _TCHAR buf[512] = {0};
-               my_sprintf_s(buf, sizeof(buf) - 1, args);
-               return do_send_log(level, domain, (const _TCHAR*)buf, (sizeof(buf) / sizeof(_TCHAR)) - 1);
+               return 0;
        }
        bool config_ok()
        {
                return m_config_ok.load();
        }
+       
+       int64_t get_buffer_bytes();
+       int64_t get_chunk_bytes();
+       int get_latency_ms();
+       int get_channels();
+       int get_sample_rate();
+       size_t get_word_size();
+       void get_buffer_parameters(int& channels, int& rate, int& latency_ms,
+                                                          size_t& word_size, int& chunk_bytes, int& buffer_bytes);
+       virtual int64_t get_bytes_available();
+       virtual int64_t get_bytes_left();
+       
+       virtual SOUND_OUTPUT_MODULE_BASE* get_real_driver()
+       {
+               return dynamic_cast<SOUND_OUTPUT_MODULE_BASE>this;
+       }
+
        virtual std::list<std::string> get_sound_devices_list()
        {
                static std::list<std::string> dummy_list;
                return dummy_list;
        }
-       const _TCHAR* get_current_device_name()
+       
+       virtual const _TCHAR* get_sound_device_name(int num)
        {
-               return (const _TCHAR*)(m_device_name.c_str());
+               return (const _TCHAR*)nullptr;
        }
+       virtual const _TCHAR* get_current_device_name()
+       {
+               return (const _TCHAR*)(_T("Empty"));
+       }
+       
        virtual void set_logger(const std::shared_ptr<CSP_Logger> logger);
        virtual void set_system_flags(const std::shared_ptr<USING_FLAGS> p);
-
-public slot:
-       bool update_rate(int& rate)
+       void* get_extra_config_ptr()
        {
-               return reconfig_sound(rate, m_channels, m_latency_ms);
+               return m_extconfig_ptr.load();
        }
-       bool update_latency(int& latency_ms)
+       int get_extra_config_bytes()
        {
-               return reconfig_sound(m_rate, m_channels, latency_ms);
+               return m_extconfig_bytes.load();
        }
-       bool update_channels(int& channels)
+       virtual bool set_extra_config(void* p, int bytes);
+       virtual bool modify_extra_config(void* p, int& bytes);
+public slot:
+       virtual void update_config() {}
+       virtual void update_extra_config() {}
+       
+       bool start();
+       bool pause();
+       bool resume();
+       bool stop();
+       bool discard();
+
+       virtual void reset_to_defalut() {} 
+       virtual void set_volume(double level) {}
+       virtual bool is_running_sound()
        {
-               return reconfig_sound(rate, m_channels, m_latency_ms);
+               return true;
        }
-       bool reconfig_sound(int& rate, int& channels, int& latency_ms)
+       bool update_rate(int rate)
        {
-               // ToDo
-               std::lock_guard<std::recursive_mutex> locker(m_locker);
-               if((rate != m_rate.load()) || (channels != m_channels.load()) || (latency_ms != m_latency_ms.load())) {
-                       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;
+               return reconfig_sound(rate, m_channels);
        }
-       void request_to_release();
-       virtual const std::string set_device_sound(const _TCHAR* driver_name, int& rate,int& channels,int& latency_ms)
+       bool update_channels(int channels)
        {
-               return std::string(_T("Empty Device"));
+               return reconfig_sound(m_rate, channels);
        }
-       virtual bool do_send_log(imt level, int domain, const _TCHAR* str, int maxlen);
-       virtual void do_set_device_by_name(QString) {};
-       virtual void do_set_device_by_number(int) {};
-       virtual void do_set_device_from_sender_object(void) {};
-       
-       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() {}
-
-       // *PURE* SLOTS
-       virtual void do_start_recording_sound() {}
-       virtual void do_stop_recording_sound() {}
-       virtual void do_restart_recording_sound() {}
-       virtual void do_request_capture_sound(int ch) {}
+       bool update_latency(int latency_ms, bool fortce = false);
+       bool reconfig_sound(int rate, int channels);
+       void request_to_release();
        
-       virtual void set_osd(OSD_BASE* p);
-       virtual void update_extra_config(void* p);
-       virtual int result_opening_external_file();
+       virtual bool do_send_log(int level, int domain, QString _str);
+       virtual bool do_send_log(int level, int domain, const _TCHAR* _str, int maxlen);
+       virtual bool do_send_log(const _TCHAR* str, int maxlen)
        {
-               return 0;
+               do_send_log(m_loglevel.load(), m_logdomain.load(), _str, maxlen);
        }
-       virtual int64_t wrote_data_to()
+       virtual bool do_send_log(const QString _str)
        {
-               return 0;
+               do_send_log(m_loglevel.load(), m_logdomain.load(), _str);
        }
-       virtual bool result_closing_external_file()
+       
+       virtual void do_set_device_by_name(QString name) {};
+       virtual void do_set_device_by_name(const _TCHAR *name)
        {
-               return true;
+               if(name != nullptr) {
+                       do_set_device_by_name(QString::fromUtf8(name));
+               }
        }
+       virtual void do_set_device_by_name(const _TCHAR *name, int maxlen)
+       {
+               if((name != nullptr) && (maxlen > 0)) {
+                       do_set_device_by_name(QString::fromUtf8(name, maxlen));
+               }
+       }
+       virtual void do_set_device_by_number(int) {};
+       
+       // This set device by device-name having QAction (as QObject).
+       virtual void do_set_device_by_name(void);
+       virtual void do_set_device_by_number(void);
+
+       // From real driver: notify to update sound devices list.
+       virtual void do_update_device_list() {}
+       
+       virtual void set_osd(OSD_BASE* p);
+
 signals:
        // loglevel, logdomain, message
        void sig_send_log(int, int, QString);
        // rate, channels, path
        void sig_req_open_sound(int, int, QString);
+       //
+       void sig_start_audio();
+       void sig_pause_audio();
+       void sig_resume_audio();
+       void sig_close_audio();
+       void sig_discard_audio();
        // 
-       void sig_req_close_sound();
-       // samples, channel, data
-       void sig_send_output_sound_data(int64_t, int, int16_t[]);
-       // update device list for ui
-       void sig_clear_sound_device();
-       // add/update device, number and name. If number < 0 append.
-       void sig_add_sound_device_name(int, QString);
-       // Send current device number and name to UI. 
-       void sig_send_current_device_description(int, QString);
-       // Notify updating devices list to UI. size, current_device_number, need_to_reconfig 
-       void sig_notify_update_devices_list(int, int, bool);
-       // notify device changed status, true = success.
-       void sig_notify_changed_device_status(bool);
        // notify completed to release sound driver.
-       void sig_released(bool);                
+       void sig_released(bool);
+       // To UI: notify reset sound device list.
+       void sig_reset_sound_device_list();
+       // To UI: notify update sound device list #arg1 to #arg2.
+       void sig_set_sound_device(int, QString);
+       // To UI: notify adding sound device list #arg1.
+       void sig_add_sound_device(QString);
 };
 
 QT_END_NAMESPACE