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;}
#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;
m_audioOutputDevice.deviceName().toLocal8Bit().constData());
#endif
}
-
+#endif
sound_samples = samples;
sound_rate = rate;
}
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);
// 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();
delete m_audioOutput;
m_audioOutput = nullptr;
}
-
+#endif
sound_ok = false;
sound_initialized = false;
}
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();
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);
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) {
"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) {
"Audio Device #%d: %s", i, tmps.toLocal8Bit().constData());
i++;
}
+ #endif
#endif
}
}
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
_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) {
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)
#endif
}
}
+ #endif
sound_started = true;
}
if(now_record_sound || now_record_video) {
}
//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;
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;
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;
m_audioOutput->reset();
}
}
+#endif
}
#endif
#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
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()
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()) {
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;
+}
{
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