Common Source Code Project for Qt (a.k.a for FM-7).
Revision | 043fdd49f9a4b26605ff3595c9aad9d0dd95ec16 (tree) |
---|---|
Time | 2022-08-17 03:08:29 |
Author | K.Ohta <whatisthis.sowhat@gmai...> |
Commiter | K.Ohta |
[OSD][SOUND][Qt][WIP] Implementing sound driver skelton.This still be work-in-progress.
@@ -695,10 +695,8 @@ public: | ||
695 | 695 | void debug_log(int level, int domain_num, char *strbuf); |
696 | 696 | virtual double get_vm_current_usec() { return 0.0; } |
697 | 697 | virtual uint64_t get_vm_current_clock_uint64() { return 0;} |
698 | - | |
699 | 698 | |
700 | 699 | std::shared_ptr<USING_FLAGS> get_config_flags(void) { return using_flags; } |
701 | - | |
702 | 700 | // Special |
703 | 701 | std::shared_ptr<CSP_Logger> get_logger(void) { return p_logger; } |
704 | 702 | virtual bool set_glview(GLDrawClass *glv) { /* Dummy */ return false;} |
@@ -450,6 +450,37 @@ void OSD_BASE::release_sound() | ||
450 | 450 | #include <QtMultimedia> |
451 | 451 | void OSD_BASE::initialize_sound(int rate, int samples, int* presented_rate, int* presented_samples) |
452 | 452 | { |
453 | +#if 0 | |
454 | + std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver; | |
455 | + disconnect(this, SIGNAL(sig_set_volume(double)), nullptr, nullptr); | |
456 | + disconnect(this, SIGNAL(sig_snd_reset_to_default()), nullptr, nullptr); | |
457 | + | |
458 | + if(out_driver.get() != nullptr) { | |
459 | + int latency_ms = (samples * 1000) / rate; | |
460 | + if(out_driver->reconfig_sound(rate, 2)) { // ToDo: Channels. | |
461 | + out_driver->update_latency(latency_ms, true); | |
462 | + rate = out_driver->get_sample_rate(); | |
463 | + latency_ms = out_driver->get_latency_ms(); | |
464 | + samples = (latency_ms * 1000) / rate; | |
465 | + } | |
466 | + sound_us_before_rendered = out_driver->driver_processed_usec(); | |
467 | + elapsed_us_before_rendered = out_driver->driver_elapsed_usec(); | |
468 | + | |
469 | + connect(this, SIGNAL(sig_snd_set_volume(double)), out_driver->get_real_driver(), SLOT(set_volume(double))); | |
470 | + connect(this, SIGNAL(sig_snd_reset_to_default()), out_driver->get_real_driver(), SLOT(reset_to_default())); | |
471 | + | |
472 | + connect(this, SIGNAL(sig_snd_request_to_release()), out_driver.get(), SLOT(request_to_release())); | |
473 | + | |
474 | + //connect(this, SIGNAL(sig_snd_update_rate(int)), out_driver.get(), SLOT(update_rate(int)), Qt::QueuedConnection); | |
475 | + //connect(this, SIGNAL(sig_snd_update_channels(int)), out_driver.get(), SLOT(update_channels(int)), Qt::QueuedConnection); | |
476 | + //connect(this, SIGNAL(sig_snd_update_latency(int)), out_driver.get(), SLOT(update_latency(int)), Qt::QueuedConnection); | |
477 | + //connect(this, SIGNAL(sig_snd_update_latency(int, bool)), out_driver.get(), SLOT(update_latency(int, bool)), Qt::QueuedConnection); | |
478 | + //connect(this, SIGNAL(sig_snd_reconfig(int, int)), out_driver.get(), SLOT(reconfig_sound(int, int)), Qt::QueuedConnection); | |
479 | + } else { | |
480 | + sound_us_before_rendered = 0; | |
481 | + elapsed_us_before_rendered = 0; | |
482 | + } | |
483 | +#else | |
453 | 484 | // ToDo: Sound Input |
454 | 485 | QAudioFormat desired; |
455 | 486 |
@@ -525,7 +556,7 @@ void OSD_BASE::initialize_sound(int rate, int samples, int* presented_rate, int* | ||
525 | 556 | m_audioOutputDevice.deviceName().toLocal8Bit().constData()); |
526 | 557 | #endif |
527 | 558 | } |
528 | - | |
559 | +#endif | |
529 | 560 | sound_samples = samples; |
530 | 561 | sound_rate = rate; |
531 | 562 |
@@ -550,11 +581,21 @@ void OSD_BASE::initialize_sound(int rate, int samples, int* presented_rate, int* | ||
550 | 581 | } |
551 | 582 | |
552 | 583 | sound_ok = true; |
584 | + #if 0 | |
585 | + if(out_driver.get() != nullptr) { | |
586 | + double _ll = 1.0; | |
587 | + if(p_config != nullptr) { | |
588 | + _ll = (double)(p_config->general_sound_level + INT16_MAX) / 65535.0; | |
589 | + } | |
590 | + emit sig_set_volume(_ll); | |
591 | + } | |
592 | + #else | |
553 | 593 | if(p_config != nullptr) { |
554 | 594 | double _ll = (double)(p_config->general_sound_level + INT16_MAX) / 65535.0; |
555 | 595 | m_audioOutputSink->setVolume(_ll); |
556 | 596 | } |
557 | 597 | connect(m_audioOutputSink.get(), SIGNAL(stateChanged(QAudio::State)), this, SLOT(handleAudioOutputStateChanged(QAudio::State))); |
598 | + #endif | |
558 | 599 | sound_initialized = true; |
559 | 600 | debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND, |
560 | 601 | "Sound OK: BufSize = %d", outbuffer_length); |
@@ -566,7 +607,11 @@ void OSD_BASE::release_sound() | ||
566 | 607 | // release Qt Multimedia sound |
567 | 608 | sound_exit = true; |
568 | 609 | sound_initialized = false; |
569 | - | |
610 | +#if 0 | |
611 | + m_output_driver->stop(); | |
612 | + m_output_driver->reset_to_default(); | |
613 | + disconnect(this, nullptr, m_output_driver.get(), nullptr); | |
614 | +#else | |
570 | 615 | m_audioOutputSink->stop(); |
571 | 616 | m_audioOutputSink->disconnect(); |
572 | 617 |
@@ -589,7 +634,7 @@ void OSD_BASE::release_sound() | ||
589 | 634 | delete m_audioOutput; |
590 | 635 | m_audioOutput = nullptr; |
591 | 636 | } |
592 | - | |
637 | +#endif | |
593 | 638 | sound_ok = false; |
594 | 639 | sound_initialized = false; |
595 | 640 | } |
@@ -597,15 +642,29 @@ void OSD_BASE::release_sound() | ||
597 | 642 | void OSD_BASE::do_update_master_volume(int level) |
598 | 643 | { |
599 | 644 | //std::lock_guard<std::recursive_timed_mutex> l(vm_mutex); |
600 | - | |
601 | 645 | double _ll = (double)(level + INT16_MAX) / 65535.0; |
646 | +#if 0 | |
647 | + static const QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_set_volume(double))); | |
648 | + if(isSignalConnected(_sig)) { | |
649 | + emit sig_set_volume(_ll); | |
650 | + } | |
651 | +#else | |
602 | 652 | m_audioOutputSink->setVolume(_ll); |
653 | +#endif | |
603 | 654 | } |
604 | 655 | |
605 | 656 | |
606 | 657 | void OSD_BASE::do_set_host_sound_output_device(QString device_name) |
607 | 658 | { |
608 | 659 | if(device_name.isEmpty()) return; |
660 | +#if 0 | |
661 | + static const QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_set_device(QString))); | |
662 | + if(isSignalConnected(_sig)) { | |
663 | + emit sig_set_device(device_name); | |
664 | + debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND, | |
665 | + "Set Audio Device to %s", device_name.toLocal8Bit().constData()); | |
666 | + } | |
667 | +#eise | |
609 | 668 | #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) |
610 | 669 | QString _older; |
611 | 670 | _older = m_audioOutputDevice.description(); |
@@ -660,10 +719,18 @@ void OSD_BASE::do_set_host_sound_output_device(QString device_name) | ||
660 | 719 | sound_samples = dummy_samples; |
661 | 720 | } |
662 | 721 | } |
722 | +#endif | |
663 | 723 | } |
664 | 724 | |
665 | 725 | const _TCHAR *OSD_BASE::get_sound_device_name(int num) |
666 | 726 | { |
727 | +#if 0 | |
728 | + std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver; | |
729 | + if(out_driver.get() != nullptr) { | |
730 | + return out_driver->get_sound_device_name(num); | |
731 | + } | |
732 | + return (const _TCHAR*)nullptr; | |
733 | +#else | |
667 | 734 | if((num < 0) || (num >= sound_device_list.count())) return (const _TCHAR *)nullptr; |
668 | 735 | |
669 | 736 | QString sdev = sound_device_list.at(num); |
@@ -671,14 +738,22 @@ const _TCHAR *OSD_BASE::get_sound_device_name(int num) | ||
671 | 738 | static QByteArray _n; |
672 | 739 | _n.clear(); |
673 | 740 | _n = sdev.toUtf8().constData(); |
674 | - | |
675 | 741 | return (const _TCHAR*)(_n.constData()); |
742 | +#endif | |
676 | 743 | } |
677 | 744 | |
678 | 745 | void OSD_BASE::get_sound_device_list() |
679 | 746 | { |
680 | - sound_device_list.clear(); | |
681 | -#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) | |
747 | +#if 0 | |
748 | + std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver; | |
749 | + if(out_driver.get() != nullptr) { | |
750 | + sound_device_list = out_driver->get_sound_devices_list(); | |
751 | + } else { | |
752 | + sound_device_list.clear(); | |
753 | + } | |
754 | +#else | |
755 | + sound_device_list.clear(); | |
756 | + #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) | |
682 | 757 | QList<QAudioDevice> tmplist = QMediaDevices::audioOutputs(); |
683 | 758 | int i = 0; |
684 | 759 | for(auto p = tmplist.begin(); p != tmplist.end(); ++p) { |
@@ -688,7 +763,7 @@ void OSD_BASE::get_sound_device_list() | ||
688 | 763 | "Audio Device #%d: %s", i, tmps.toLocal8Bit().constData()); |
689 | 764 | i++; |
690 | 765 | } |
691 | -#elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0) | |
766 | + #elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0) | |
692 | 767 | QList<QAudioDeviceInfo> tmplist = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput); |
693 | 768 | int i = 0; |
694 | 769 | for(auto p = tmplist.begin(); p != tmplist.end(); ++p) { |
@@ -698,6 +773,7 @@ void OSD_BASE::get_sound_device_list() | ||
698 | 773 | "Audio Device #%d: %s", i, tmps.toLocal8Bit().constData()); |
699 | 774 | i++; |
700 | 775 | } |
776 | + #endif | |
701 | 777 | #endif |
702 | 778 | } |
703 | 779 |
@@ -1214,19 +1290,35 @@ void OSD_BASE::handleAudioOutputStateChanged(QAudio::State newState) | ||
1214 | 1290 | } |
1215 | 1291 | void OSD_BASE::update_sound(int* extra_frames) |
1216 | 1292 | { |
1217 | - *extra_frames = 0; | |
1218 | - | |
1219 | - #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) | |
1220 | - std::shared_ptr<QAudioSink>sink_ptr = m_audioOutputSink; | |
1293 | + if(extra_frames != nullptr) { | |
1294 | + *extra_frames = 0; | |
1295 | + } | |
1296 | + #if 0 | |
1297 | + std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver; | |
1221 | 1298 | #else |
1299 | + #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) | |
1300 | + std::shared_ptr<QAudioSink>sink_ptr = m_audioOutputSink; | |
1301 | + #else | |
1222 | 1302 | std::shared_ptr<QAudioOutput>sink_ptr = m_audioOutputSink; |
1223 | - #endif | |
1303 | + #endif | |
1304 | + #endif | |
1224 | 1305 | now_mute = false; |
1225 | 1306 | if(sound_ok) { |
1307 | + #if 0 | |
1308 | + int64_t elapsed_us_now = 0; | |
1309 | + int64_t sound_us_now = 0; | |
1310 | + int64_t _period_usec = 100 * 1000; | |
1311 | + if(out_driver.get() != nullptr) { | |
1312 | + elapsed_us_now = out_driver->driver_elapsed_usec(); | |
1313 | + sound_us_now = out_driver->driver_processed_usec(); | |
1314 | + _period_usec = out_driver->get_latency_ms() * 1000; | |
1315 | + } | |
1316 | + #else | |
1226 | 1317 | //debug_log(CSP_LOG_INFO, CSP_LOG_TYPE_SOUND, "Sink->bytesFree() = %d", m_audioOutputSink->bytesFree()); |
1227 | 1318 | const int64_t elapsed_us_now = (int64_t)(sink_ptr->elapsedUSecs()); |
1228 | 1319 | const int64_t sound_us_now = (int64_t)(sink_ptr->processedUSecs()); |
1229 | 1320 | const int64_t _period_usec = (((int64_t)sound_samples * (int64_t)10000) / (int64_t)sound_rate) * 100; |
1321 | + #endif | |
1230 | 1322 | int64_t _diff = sound_us_now - (int64_t)sound_us_before_rendered; |
1231 | 1323 | if((_diff < 0) && ((INT64_MAX - (int64_t)sound_us_before_rendered + 1) <= _period_usec)) { |
1232 | 1324 | // For uS overflow |
@@ -1238,22 +1330,16 @@ void OSD_BASE::update_sound(int* extra_frames) | ||
1238 | 1330 | _diff2 = elapsed_us_now + (INT64_MAX - (int64_t)elapsed_us_before_rendered + 1); |
1239 | 1331 | } |
1240 | 1332 | |
1241 | - int now_mixed_ptr = 0; | |
1242 | - if(vm != nullptr) { | |
1243 | - now_mixed_ptr = vm->get_sound_buffer_ptr(); | |
1244 | - } | |
1245 | 1333 | if((sound_started) && (_diff2 < (_period_usec - 2000))) { // 2mSec |
1246 | 1334 | return; |
1247 | 1335 | } |
1248 | -// if((sound_started) && (_diff2 < (_period_usec - 5000))) { // 5mSec | |
1249 | -// if((sound_started) && (_diff < (_period_usec - 0))) { // 2mSec | |
1250 | -// return; | |
1251 | -// } | |
1252 | -// } | |
1253 | -// if(now_mixed_ptr < ((sound_samples * 100) / 100)) { | |
1254 | - // Render even emulate 100% of latency when remain seconds is less than 2m Sec. | |
1255 | -// return; | |
1256 | -// } | |
1336 | + #if 0 | |
1337 | + if(out_driver.get() != nullptr) { | |
1338 | + if(out_driver->get_bytes_left() < out_driver->get_chunk_bytes()) { | |
1339 | + return; | |
1340 | + } | |
1341 | + } | |
1342 | + #else | |
1257 | 1343 | qint64 left = 0; |
1258 | 1344 | qint64 _size = sound_samples * 2 * sizeof(int16_t) * 4; |
1259 | 1345 | if(m_audioOutput != nullptr) { |
@@ -1262,11 +1348,27 @@ void OSD_BASE::update_sound(int* extra_frames) | ||
1262 | 1348 | if(left < (sound_samples * 2 * sizeof(int16_t))) { |
1263 | 1349 | return; |
1264 | 1350 | } |
1351 | + #endif | |
1265 | 1352 | |
1266 | 1353 | // Input |
1267 | 1354 | int16_t* sound_buffer = (int16_t*)create_sound(extra_frames); |
1268 | 1355 | |
1269 | 1356 | if(sound_buffer != nullptr) { |
1357 | + #if 0 | |
1358 | + if(out_driver.get() != nullptr) { | |
1359 | + if(!(sound_started)) { | |
1360 | + out_driver->start(); | |
1361 | + elapse_us_before_rendered = out_driver->driver_elapsed_usec(); | |
1362 | + sound_us_before_rendered = out_driver->driver_processed_usec(); | |
1363 | + } else { | |
1364 | + if(_diff2 > (_period_usec * 2)) { | |
1365 | + out_driver->discard(); | |
1366 | + elapse_us_before_rendered = out_driver->driver_elapsed_usec(); | |
1367 | + sound_us_before_rendered = out_driver->driver_processed_usec(); | |
1368 | + } | |
1369 | + } | |
1370 | + } | |
1371 | + #else | |
1270 | 1372 | if(!(sound_started)) { |
1271 | 1373 | m_audioOutput->reset(); |
1272 | 1374 | #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) |
@@ -1293,6 +1395,7 @@ void OSD_BASE::update_sound(int* extra_frames) | ||
1293 | 1395 | #endif |
1294 | 1396 | } |
1295 | 1397 | } |
1398 | + #endif | |
1296 | 1399 | sound_started = true; |
1297 | 1400 | } |
1298 | 1401 | if(now_record_sound || now_record_video) { |
@@ -1323,6 +1426,16 @@ void OSD_BASE::update_sound(int* extra_frames) | ||
1323 | 1426 | } |
1324 | 1427 | //if(sound_initialized) return; |
1325 | 1428 | if(sound_buffer != nullptr) { |
1429 | + #if 0 | |
1430 | + if(out_driver.get() != nullptr) { | |
1431 | + out_driver->update_sound((void *)sound_buffer, -1); | |
1432 | + elapse_us_before_rendered = out_driver->driver_elapsed_usec(); | |
1433 | + sound_us_before_rendered = out_driver->driver_processed_usec(); | |
1434 | + } else { | |
1435 | + elapse_us_before_rendered = 0; | |
1436 | + sound_us_before_rendered = 0; | |
1437 | + } | |
1438 | + #else | |
1326 | 1439 | if((m_audioOutput != nullptr) /*&& (m_audioOutputSink != nullptr)*/) { |
1327 | 1440 | // ToDo: Not Int16. |
1328 | 1441 | //qint64 sound_len = sound_samples * sound_rate * 2 * wordsize; |
@@ -1335,11 +1448,29 @@ void OSD_BASE::update_sound(int* extra_frames) | ||
1335 | 1448 | elapsed_us_before_rendered = sink_ptr->elapsedUSecs(); |
1336 | 1449 | } |
1337 | 1450 | } |
1451 | + #endif | |
1338 | 1452 | } |
1339 | 1453 | } |
1340 | 1454 | |
1341 | 1455 | void OSD_BASE::mute_sound() |
1342 | 1456 | { |
1457 | +#if 0 | |
1458 | + if(!(now_mute) && (sound_ok)) { | |
1459 | + std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver; | |
1460 | + if(out_driver.get() != nullptr) { | |
1461 | + int64_t _samples = out_driver->get_buffer_bytes(); | |
1462 | + uint8_t* p = new uint8_t[_samples]; | |
1463 | + out_driver->discard(); | |
1464 | + if(p != nullptr) { | |
1465 | + memset(p, 0x00, _samples); | |
1466 | + out_driver->update_sound((void *)p, _samples); | |
1467 | + delete[] p; | |
1468 | + } | |
1469 | + sound_us_before_rendered = out_driver->driver_processed_usec(); | |
1470 | + elapsed_us_before_rendered = out_driver->driver_elapsed_usec(); | |
1471 | + } | |
1472 | + } | |
1473 | +#else | |
1343 | 1474 | if(!(now_mute) && (sound_ok)) { |
1344 | 1475 | #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) |
1345 | 1476 | std::shared_ptr<QAudioSink>sink_ptr = m_audioOutputSink; |
@@ -1359,10 +1490,21 @@ void OSD_BASE::mute_sound() | ||
1359 | 1490 | sound_us_before_rendered = sink_ptr->processedUSecs(); |
1360 | 1491 | elapsed_us_before_rendered = sink_ptr->elapsedUSecs(); |
1361 | 1492 | } |
1493 | +#endif | |
1362 | 1494 | now_mute = true; |
1363 | 1495 | } |
1364 | 1496 | void OSD_BASE::stop_sound() |
1365 | 1497 | { |
1498 | +#if 0 | |
1499 | + if((sound_ok) && (sound_started)) { | |
1500 | + std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver; | |
1501 | + if(out_driver.get() != nullptr) { | |
1502 | + out_driver->stop(); | |
1503 | + } | |
1504 | + sound_us_before_rendered = 0; | |
1505 | + elapsed_us_before_rendered = 0; | |
1506 | + } | |
1507 | +#else | |
1366 | 1508 | if((sound_ok) && (sound_started)) { |
1367 | 1509 | #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) |
1368 | 1510 | std::shared_ptr<QAudioSink>sink_ptr = m_audioOutputSink; |
@@ -1385,6 +1527,7 @@ void OSD_BASE::stop_sound() | ||
1385 | 1527 | m_audioOutput->reset(); |
1386 | 1528 | } |
1387 | 1529 | } |
1530 | +#endif | |
1388 | 1531 | } |
1389 | 1532 | |
1390 | 1533 | #endif |
@@ -1467,7 +1610,15 @@ int OSD_BASE::get_sound_rate() | ||
1467 | 1610 | #else |
1468 | 1611 | int OSD_BASE::get_sound_rate() |
1469 | 1612 | { |
1613 | +#if 0 | |
1614 | + std::shared_ptr<SOUND_OUTPUT_MODULE_BASE>out_driver = m_output_driver; | |
1615 | + if(out_driver.get() != nullptr) { | |
1616 | + return out_driver->get_sample_rate(); | |
1617 | + } | |
1618 | + return 48000; | |
1619 | +#else | |
1470 | 1620 | return (int)(m_audioOutputFormat.sampleRate()); |
1621 | +#endif | |
1471 | 1622 | } |
1472 | 1623 | #endif |
1473 | 1624 |
@@ -2,39 +2,43 @@ | ||
2 | 2 | |
3 | 3 | |
4 | 4 | SOUND_OUTPUT_MODULE_BASE::SOUND_OUTPUT_MODULE_BASE(OSD_BASE *parent, |
5 | - _TCHAR* device_name, | |
5 | + SOUND_BUFFER_QT* deviceIO, | |
6 | 6 | int base_rate, |
7 | 7 | int base_latency_ms, |
8 | 8 | int base_channels, |
9 | 9 | void *extra_config_values) |
10 | - : m_OSD(parent), | |
10 | + : | |
11 | 11 | m_config_ok(false), |
12 | 12 | m_rate(base_rate), |
13 | 13 | m_latency_ms(base_latency_ms), |
14 | 14 | m_channels(base_channels), |
15 | 15 | m_extconfig(extra_config_values), |
16 | + m_wordsize(sizeof(int16_t)), | |
16 | 17 | QObject(qobject_cast<QObject*>parent) |
17 | 18 | { |
18 | 19 | m_device.clear(); |
19 | - if(m_OSD != nullptr) { | |
20 | - m_logger = m_OSD->get_logger(); | |
21 | - m_using_flags = m_OSD->get_config_flags(); | |
22 | - } | |
23 | - if(m_logger.get() != nullptr) { | |
24 | - QObject::connect(this, SIGNAL(sig_send_log(int, int, QString)), | |
25 | - m_logger.get(), SLOT(do_debug_log(int, int, QString)), | |
26 | - Qt::QueueedConnection); | |
20 | + | |
21 | + m_logger.reset(); | |
22 | + m_using_flags.reset(); | |
23 | + set_osd(parent); | |
24 | + | |
25 | + if(deviceIO != nullptr) { | |
26 | + m_fileio.reset(deviceIO); | |
27 | + m_buffer_bytes = deviceIO->size(); | |
28 | + m_chunk_bytes = m_buffer_bytes / 4; | |
29 | + } else { | |
30 | + if(m_channels < 1) m_channels = 1; | |
31 | + if(m_rate < 1000) m_rate = 1000; | |
32 | + m_chunk_bytes = ((qint64)(m_channels * m_wordsize * latency_ms) * (quint64)m_rate) / 1000; | |
33 | + m_buffer_bytes = m_chunk_bytes * 4; | |
34 | + m_fileio.reset(new SOUND_BUFFER_QT(m_buffer_bytes, this)); | |
27 | 35 | } |
36 | + | |
28 | 37 | m_loglevel = CSP_LOG_INFO; |
29 | 38 | m_logdomain = CSP_LOG_TYPE_SOUND; |
39 | + m_device_name.clear(); | |
30 | 40 | |
31 | - if(device_name == nullptr) { | |
32 | - m_device_name = std::string(_T("Default")); | |
33 | - } else { | |
34 | - QString tmpname = QString::fromUtf8(device_name); | |
35 | - m_device_name = tmpname.toStdString(); | |
36 | - } | |
37 | - m_config_ok = false; | |
41 | + initialize_driver(); | |
38 | 42 | } |
39 | 43 | |
40 | 44 | SOUND_OUTPUT_MODULE_BASE::~SOUND_OUTPUT_MODULE_BASE() |
@@ -42,9 +46,12 @@ SOUND_OUTPUT_MODULE_BASE::~SOUND_OUTPUT_MODULE_BASE() | ||
42 | 46 | if(m_config_ok.load()) { |
43 | 47 | release_driver(); |
44 | 48 | } |
49 | + m_fileio.reset(); | |
50 | + | |
45 | 51 | m_config_ok = false; |
46 | 52 | } |
47 | 53 | |
54 | + | |
48 | 55 | void SOUND_OUTPUT_MODULE_BASE::request_to_release() |
49 | 56 | { |
50 | 57 | if(m_config_ok.load()) { |
@@ -53,45 +60,367 @@ void SOUND_OUTPUT_MODULE_BASE::request_to_release() | ||
53 | 60 | emit sig_released(!(m_config_ok.load())); |
54 | 61 | } |
55 | 62 | |
56 | -bool SOUND_OUTPUT_MODULE_BASE::do_send_log(int level, int domain, const _TCHAR* str, int maxlen) | |
63 | +std::shared_ptr<QIODevice> SOUND_OUTPUT_MODULE_BASE::set_io_device(QIODevice *p) | |
57 | 64 | { |
58 | - __UNLIKELY_IF((str == nullptr) || (maxlen <= 0)) return false; | |
59 | - __UNLIKELY_IF(strlen(str) <= 0) return false; | |
60 | - QString s = QString::fromUtf8(buf); | |
61 | - emit sig_send_log(level, domain, s); | |
62 | - return true; | |
65 | + | |
66 | + bool _f = is_running_sound(); | |
67 | + if(m_fileio.get() != nullptr) { | |
68 | + _f &= m_fileio->isOpen(); | |
69 | + } | |
70 | + stop(); | |
71 | + if(p == nullptr) { | |
72 | + m_fileio.reset(new SOUND_BUFFER_QT(m_chunk_bytes * 4, this)); | |
73 | + } else { | |
74 | + m_fileio.reset(p); | |
75 | + } | |
76 | + update_driver_fileio(); | |
77 | + if(_f) { | |
78 | + start(); | |
79 | + } | |
80 | + return m_fileio; | |
81 | +} | |
82 | + | |
83 | +std::shared_ptr<QIODevice> SOUND_OUTPUT_MODULE_BASE::set_io_device(std::shared_ptr<QIODevice> ps) | |
84 | +{ | |
85 | + bool _f = is_running_sound(); | |
86 | + if(m_fileio.get() != nullptr) { | |
87 | + _f &= m_fileio->isOpen(); | |
88 | + } | |
89 | + stop(); | |
90 | + m_fileio = ps; | |
91 | + update_driver_fileio(); | |
92 | + if(_f) { | |
93 | + start(); | |
94 | + } | |
95 | + return m_fileio; | |
96 | +} | |
97 | + | |
98 | + | |
99 | +bool SOUND_OUTPUT_MODULE_BASE::update_latency(int latency_ms, bool force) | |
100 | +{ | |
101 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
102 | + if(latency_ms <= 0) { | |
103 | + return false; | |
104 | + } | |
105 | + if(!(force) && (m_latency_ms == latency_ms)) return true; | |
106 | + | |
107 | + m_latency_ms = latency_ms; | |
108 | + m_chunk_bytes = ((qint64)(m_channels * ((int)m_wordsize) * latency_ms) * (quint64)m_rate) / 1000; | |
109 | + m_buffer_bytes = m_chunk_bytes * 4; | |
110 | + | |
111 | + stop(); | |
112 | + | |
113 | + std::shared_ptr<SOUND_BUFFER_QT> q = m_fileio; | |
114 | + if(q.get() != nullptr) { | |
115 | + q->reset(); | |
116 | + if(!(q->resize(m_buffer_bytes))) { | |
117 | + q->reset(); | |
118 | + m_buffer_bytes = (int64_t)(q->size()); | |
119 | + } | |
120 | + } else { | |
121 | + m_fileio.reset(new SOUND_BUFFER_QT(m_buffer_bytes, this)); | |
122 | + } | |
123 | + update_driver_fileio(); | |
124 | + return (start() && (m_fileio.get() != nullptr)); | |
125 | +} | |
126 | + | |
127 | + | |
128 | +bool SOUND_OUTPUT_MODULE_BASE::reconfig_sound(int rate, int channels) | |
129 | +{ | |
130 | + // ToDo | |
131 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
132 | + if((rate != m_rate) || (channels != m_channels)) { | |
133 | + if(real_reconfig_sound(rate, channels)) { | |
134 | + m_rate = rate; | |
135 | + m_channels = channels; | |
136 | + m_config_ok = update_latency(m_latency_ms, true); | |
137 | + return m_config_ok.load(); | |
138 | + } | |
139 | + } | |
140 | + return false; | |
141 | +} | |
142 | + | |
143 | +int64_t SOUND_OUTPUT_MODULE_BASE::update_sound(void* datasrc, int samples) | |
144 | +{ | |
145 | + std::shared_ptr<SOUND_BUFFER_QT>q = m_fileio; | |
146 | + | |
147 | + if(q.get() == nullptr) return -1; | |
148 | + | |
149 | + if(samples > 0) { | |
150 | + qint64 _size = (qint64)(samples * m_channels) * (qint64)m_wordsize; | |
151 | + return (int64_t)q->write((const char *)datasrc, _size); | |
152 | + } else if(samples < 0) { | |
153 | + return (int64_t)q->write((const char *)datasrc, m_chunk_bytes); | |
154 | + } | |
155 | + return -1; | |
156 | +} | |
157 | + | |
158 | +bool SOUND_OUTPUT_MODULE_BASE::start() | |
159 | +{ | |
160 | + std::shared_ptr<SOUND_BUFFER_QT>q = m_fileio; | |
161 | + if(is_running_sound()) { // ToDo: STOP | |
162 | + stop(); | |
163 | + } | |
164 | + bool _stat = false; | |
165 | + | |
166 | + if(q.get() != nullptr) { | |
167 | + _stat = q->open(QIODeviceBase::Write | QIODeviceBase::Unbuffered); | |
168 | + update_driver_fileio(); | |
169 | + } | |
170 | + if(_stat) { | |
171 | + QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_start_audio())); | |
172 | + if(isSignalConnected(_sig)) { | |
173 | + emit sig_start_audio(); | |
174 | + } | |
175 | + } | |
176 | + return _stat; | |
177 | +} | |
178 | + | |
179 | +bool SOUND_OUTPUT_MODULE_BASE::pause() | |
180 | +{ | |
181 | + QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_pause_audio())); | |
182 | + if(isSignalConnected(_sig)) { | |
183 | + emit sig_pause_audio(); | |
184 | + return true; | |
185 | + } | |
186 | + return false; | |
187 | +} | |
188 | + | |
189 | +bool SOUND_OUTPUT_MODULE_BASE::resume() | |
190 | +{ | |
191 | + QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_resume_audio())); | |
192 | + if(isSignalConnected(_sig)) { | |
193 | + emit sig_resume_audio(); | |
194 | + return true; | |
195 | + } | |
196 | + return false; | |
197 | +} | |
198 | + | |
199 | +bool SOUND_OUTPUT_MODULE_BASE::stop() | |
200 | +{ | |
201 | + bool _stat = false; | |
202 | + QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_close_audio())); | |
203 | + if(isSignalConnected(_sig)) { | |
204 | + emit sig_close_audio(); | |
205 | + _stat = true; | |
206 | + } | |
207 | + std::shared_ptr<SOUND_BUFFER_QT>q = m_fileio; | |
208 | + | |
209 | + if(q.get() != nullptr) { | |
210 | + if(q->isOpen()) { | |
211 | + q->close(); | |
212 | + } | |
213 | + return _stat; | |
214 | + } | |
215 | + return false; | |
216 | +} | |
217 | + | |
218 | +bool SOUND_OUTPUT_MODULE_BASE::discard() | |
219 | +{ | |
220 | +// std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
221 | +// std::shared_ptr<SOUND_BUFFER_QT> q = m_fileio; | |
222 | +// if(q.get() != nullptr) { | |
223 | + QMetaMethod _sig = QMetaMethod::fromSignal(SIGNAL(sig_discard_audio())); | |
224 | + if(isSignalConnected(_sig)) { | |
225 | + emit sig_discard_audio(); | |
226 | + return true; | |
227 | + } | |
228 | +// } | |
229 | + return false; | |
63 | 230 | } |
64 | 231 | |
232 | +void SOUND_OUTPUT_MODULE_BASE::do_set_device_by_name(void) | |
233 | +{ | |
234 | + QAction *cp = qobject_cast<QAction*>(QObject::sender()); | |
235 | + if(cp == nullptr) return; | |
236 | + QString _id = cp->data().value<QString>(); | |
237 | + do_set_device_by_name(_id); | |
238 | +} | |
239 | + | |
240 | +void SOUND_OUTPUT_MODULE_BASE::do_set_device_by_number(void) | |
241 | +{ | |
242 | + QAction *cp = qobject_cast<QAction*>(QObject::sender()); | |
243 | + if(cp == nullptr) return; | |
244 | + int _id = cp->data().value<int>(); | |
245 | + do_set_device_by_number(_id); | |
246 | +} | |
247 | + | |
248 | + | |
249 | +bool SOUND_OUTPUT_MODULE_BASE::do_send_log(int level, int domain, const _TCHAR* _str, int maxlen) | |
250 | +{ | |
251 | + __UNLIKELY_IF((_str == nullptr) || (maxlen <= 0)) return false; | |
252 | + __UNLIKELY_IF(strlen(_str) <= 0) return false; | |
253 | + | |
254 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
255 | + __LIKELY_IF(isSignalConnected(SIGNAL(sig_send_log(int, int, const _TCHAR*, int)))) { | |
256 | + emit sig_send_log(level, domain, _str, maxlen); | |
257 | + return true; | |
258 | + } | |
259 | + | |
260 | + QString s = QString::fromUtf8(_str, maxlen); | |
261 | + | |
262 | + __LIKELY_IF(isSignalConnected(SIGNAL(sig_send_log(int, int, QString)))) { | |
263 | + emit sig_send_log(level, domain, s); | |
264 | + return true; | |
265 | + } | |
266 | + return false; | |
267 | +} | |
268 | + | |
269 | +bool SOUND_OUTPUT_MODULE_BASE::do_send_log(int level, int domain, const QString _str) | |
270 | +{ | |
271 | + __UNLIKELY_IF(str.isEmpty()) return false; | |
272 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
273 | + | |
274 | + __LIKELY_IF(isSignalConnected(SIGNAL(sig_send_log(int, int, QString)))) { | |
275 | + emit sig_send_log(level, domain, _str); | |
276 | + return true; | |
277 | + } | |
278 | + return false; | |
279 | +} | |
280 | + | |
281 | + | |
65 | 282 | void SOUND_OUTPUT_MODULE_BASE::set_logger(const std::shared_ptr<CSP_Logger> logger) |
66 | 283 | { |
67 | - std::lock_guard<std::recursive_mutex> locker(m_locker); | |
284 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
68 | 285 | if(m_logger.get() != nullptr) { |
69 | - QObject::disconnect(this, SIGNAL(sig_send_log(int, int, QString)), | |
70 | - m_logger.get(), SLOT(do_debug_log(int, int, QString))); | |
286 | + disconnect(this, nullptr, m_logger.get(), nullptr); | |
71 | 287 | } |
72 | 288 | m_logger = logger; |
73 | 289 | if(m_logger.get() != nullptr) { |
74 | - QObject::connect(this, SIGNAL(sig_send_log(int, int, QString)), | |
75 | - m_logger.get(), SLOT(do_debug_log(int, int, QString)), | |
76 | - Qt::QueueedConnection); | |
290 | + connect(this, SIGNAL(sig_send_log(int, int, QString)), | |
291 | + m_logger.get(), SLOT(do_send_log(int, int, QString)), | |
292 | + Qt::QueuedConnection); | |
77 | 293 | } |
78 | 294 | } |
295 | + | |
79 | 296 | void SOUND_OUTPUT_MODULE_BASE::set_osd(OSD_BASE* p) |
80 | 297 | { |
81 | - std::lock_guard<std::recursive_mutex> locker(m_locker); | |
82 | - m_OSD = p; | |
298 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
299 | + if(p != nullptr) { | |
300 | + m_OSD = p; | |
301 | + set_logger(p->get_logger()); | |
302 | + set_system_flags(p->get_config_flags()); | |
303 | + } else { | |
304 | + m_OSD = nullptr; | |
305 | + if(m_logger.get() != nullptr) { | |
306 | + disconnect(this, nullptr, m_logger.get(), nullptr); | |
307 | + } | |
308 | + m_logger.reset(); | |
309 | + m_using_flags.reset(); | |
310 | + } | |
83 | 311 | } |
84 | 312 | |
85 | 313 | void SOUND_OUTPUT_MODULE_BASE::set_system_flags(const std::shared_ptr<USING_FLAGS> p) |
86 | 314 | { |
87 | - std::lock_guard<std::recursive_mutex> locker(m_locker); | |
88 | 315 | m_using_flags = p; |
316 | + update_config(); | |
317 | +} | |
318 | + | |
319 | +bool SOUND_OUTPUT_MODULE_BASE::set_extra_config(void* p, int bytes) | |
320 | +{ | |
321 | + if((p == nullptr) || (bytes <= 0)) { | |
322 | + return false; | |
323 | + } | |
324 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
325 | + m_extconfig_ptr = p; | |
326 | + m_extconfig_bytes = bytes; | |
327 | + update_extra_config(); | |
328 | + return true; | |
89 | 329 | } |
90 | 330 | |
91 | -void SOUND_OUTPUT_MODULE_BASE::update_extra_config(void* p) | |
331 | +bool SOUND_OUTPUT_MODULE_BASE::modify_extra_config(void* p, int& bytes) | |
92 | 332 | { |
93 | - std::lock_guard<std::recursive_mutex> locker(m_locker); | |
94 | - m_extconfig = p; | |
95 | - // more lock via m_locker_outqueue etc, if needs. | |
333 | + if((p == nullptr) || (bytes <= 0)) { | |
334 | + return false; | |
335 | + } | |
336 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
337 | + uint8_t* q = (uint8_t*)(m_extconfig_ptr.load()); | |
338 | + if(q == nullptr) { | |
339 | + return false; | |
340 | + } | |
341 | + bytes = std::min(bytes, m_extconfig_bytes.load()); | |
342 | + memcpy(q, p, bytes); | |
343 | + update_extra_config(); | |
344 | + return true; | |
96 | 345 | } |
97 | 346 | |
347 | +bool SOUND_OUTPUT_MODULE_BASE::is_io_device_exists() | |
348 | +{ | |
349 | + std::shared_ptr<QIODevice> p = m_fileio; | |
350 | + if(p.get() != nullptr) { | |
351 | + return true; | |
352 | + } | |
353 | + return false; | |
354 | +} | |
355 | + | |
356 | +int64_t SOUND_OUTPUT_MODULE_BASE::get_buffer_bytes() | |
357 | +{ | |
358 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
359 | + return m_buffer_bytes; | |
360 | +} | |
361 | + | |
362 | +int64_t SOUND_OUTPUT_MODULE_BASE::get_chunk_bytes() | |
363 | +{ | |
364 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
365 | + return m_chunk_bytes; | |
366 | +} | |
367 | + | |
368 | +int SOUND_OUTPUT_MODULE_BASE::get_latency_ms() | |
369 | +{ | |
370 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
371 | + return m_latency_ms; | |
372 | +} | |
373 | + | |
374 | +int SOUND_OUTPUT_MODULE_BASE::get_channels() | |
375 | +{ | |
376 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
377 | + return m_channels; | |
378 | +} | |
379 | + | |
380 | +int SOUND_OUTPUT_MODULE_BASE::get_sample_rate() | |
381 | +{ | |
382 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
383 | + return m_rate; | |
384 | +} | |
385 | + | |
386 | +size_t SOUND_OUTPUT_MODULE_BASE::get_word_size() | |
387 | +{ | |
388 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
389 | + return m_wordsize; | |
390 | +} | |
391 | + | |
392 | +void SOUND_OUTPUT_MODULE_BASE::get_buffer_parameters(int& channels, int& rate, | |
393 | + int& latency_ms, size_t& word_size, | |
394 | + int& chunk_bytes, int& buffer_bytes) | |
395 | +{ | |
396 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
397 | + channels = m_channels; | |
398 | + rate = m_rate; | |
399 | + latency_ms = m_latency_ms; | |
400 | + word_size = m_wordsize; | |
401 | + chunk_bytes = m_chunk_bytes; | |
402 | + buffer_bytes = m_buffer_bytes; | |
403 | +} | |
404 | + | |
405 | +int64_t SOUND_OUTPUT_MODULE_BASE::get_bytes_available() | |
406 | +{ | |
407 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
408 | + std::shared_ptr<SOUND_BUFFER_QT> p = m_fileio; | |
409 | + if(p.get() != nullptr) { | |
410 | + return p->bytesAvailable(); | |
411 | + } | |
412 | + return 0; | |
413 | +} | |
414 | + | |
415 | +int64_t SOUND_OUTPUT_MODULE_BASE::get_bytes_left() | |
416 | +{ | |
417 | + std::lock_guard<std::recursive_timed_mutex> locker(m_locker); | |
418 | + std::shared_ptr<SOUND_BUFFER_QT> p = m_fileio; | |
419 | + | |
420 | + if(p.get() != nullptr) { | |
421 | + int64_t n = m_buffer_bytes - p->bytesAvailable(); | |
422 | + if(n < 0) n = 0; | |
423 | + return n; | |
424 | + } | |
425 | + return 0; | |
426 | +} |
@@ -26,169 +26,233 @@ class DLL_PREFIX SOUND_OUTPUT_MODULE_BASE : public QObject | ||
26 | 26 | { |
27 | 27 | Q_OBJECT |
28 | 28 | protected: |
29 | - OSD_BASE *m_OSD; | |
30 | - std::shared_ptr<USING_FLAGS> m_using_flags; | |
31 | - std::shared_ptr<CSP_Logger> m_logger; | |
32 | - | |
33 | - std::atomic_bool m_config_ok; | |
34 | - std::atomic<void *> m_extconfig; | |
35 | - std::atomic<int> m_rate; | |
36 | - std::atomic<int> m_channels; | |
37 | - std::atomic<int> m_latency_ms; | |
38 | - std::recursive_mutex m_locker; | |
39 | - std::atomic<int> m_loglevel; | |
40 | - std::atomic<int> m_logdomain; | |
41 | - std::string m_device_name; | |
42 | - | |
43 | - bool m_initialized; | |
29 | + OSD* m_OSD; | |
30 | + std::shared_ptr<SOUND_BUFFER_QT> m_fileio; | |
31 | + std::shared_ptr<USING_FLAGS> m_using_flags; | |
32 | + | |
33 | + std::atomic<bool> m_config_ok; | |
34 | + | |
35 | + int64_t m_chunk_bytes; | |
36 | + int64_t m_buffer_bytes; | |
37 | + | |
38 | + int m_rate; | |
39 | + int m_latency_ms; | |
40 | + int m_channels; | |
41 | + size_t m_wordsize; | |
42 | + std::atomic<void*> m_extconfig_ptr; | |
43 | + std::atomic<int> m_extconfig_bytes; | |
44 | + std::atomic<int> m_loglevel; | |
45 | + std::atomic<int> m_logdomain; | |
46 | + | |
47 | + virtual void update_driver_fileio() | |
48 | + { | |
49 | + release_driver_fileio(); | |
50 | + // Update driver side of fileio by m_fileio; | |
51 | + //connect(m_fileio.get(), SIGNAL(bytesWritten(qint64)), real_driver, SLOT, QObject::DirectConnection); | |
52 | + //connect(m_fileio.get(), SIGNAL(aboutToClose()), real_driver, SLOT, QObject::DirectConnection); | |
53 | + // Optional: | |
54 | + // connect(m_fileio.get(), SIGNAL(readyRead()), real_driver, SLOT, QObject::DirectConnection); | |
55 | + } | |
56 | + | |
57 | + virtual void release_driver_fileio() | |
58 | + { | |
59 | + // Maybe disconnect some signals via m_fileio. | |
60 | + } | |
61 | + | |
62 | + template <class... Args> | |
63 | + bool debug_log(Args... args) | |
64 | + { | |
65 | + _TCHAR buf[1024]; | |
66 | + memset(buf, 0x00, sizeof(buf)); | |
67 | + my_sprintf_s(buf, sizeof(buf) - 1, args); | |
68 | + | |
69 | + return do_send_log(m_loglevel.load(), m_logdomain.load(), | |
70 | + QString::fromUtf8(buf, sizeof(buf))); | |
71 | + } | |
44 | 72 | |
45 | 73 | public: |
46 | - SOUND_OUTPUT_MODULE_BASE( | |
47 | - OSD_BASE *parent, | |
48 | - _TCHAR* device_name, | |
49 | - const std::shared_ptr<CSP_Logger> logger, | |
50 | - const std::shared_ptr<USING_FLAGS> pflags, | |
51 | - int base_rate = 48000, | |
52 | - int base_latency_ms = 100, | |
53 | - int base_channels = 2, | |
54 | - void *extra_config_values = nullptr); | |
74 | + SOUND_OUTPUT_MODULE_BASE(OSD_BASE *parent, | |
75 | + SOUND_BUFFER_QT* deviceIO = nullptr, | |
76 | + int base_rate = 48000, | |
77 | + int base_latency_ms = 100, | |
78 | + int base_channels = 2, | |
79 | + void *extra_config_values = nullptr); | |
55 | 80 | ~SOUND_OUTPUT_MODULE_BASE(); |
56 | 81 | |
57 | - virtual bool initialize_driver() { return true; } | |
58 | - virtual bool release_driver() { return true; } | |
59 | - int get_sound_rate() | |
82 | + std::recursive_timed_mutex m_locker; | |
83 | + | |
84 | + virtual void initialize_driver() | |
60 | 85 | { |
61 | - return m_rate.load(); | |
86 | + // AT LEAST: | |
87 | + // connect(this, SIGNAL(sig_start_audio()), ..., QObject::QueuedConnection); | |
88 | + // connect(this, SIGNAL(sig_pause_audio()), ..., QObject::QueuedConnection); | |
89 | + // connect(this, SIGNAL(sig_resume_audio()), ..., QObject::QueuedConnection); | |
90 | + // connect(this, SIGNAL(sig_close_audio()), ..., QObject::QueuedConnection); | |
91 | + // connect(this, SIGNAL(sig_discard_audio()), ..., QObject::QueuedConnection); | |
92 | + // connect(this, SIGNAL(sig_released(bool)), ..., QObject::QueuedConnection); | |
93 | + // connect(this, SIGNAL(sig_req_open_sound(int, int, QString)), ..., QObject::QueuedConnection); | |
94 | + | |
95 | + // For Logging | |
96 | + // connect(real_driver, SIGNAL(sig_log(QString)), this, SLOT(do_send_log(QString)), QObject::QueuedConnection); | |
97 | + // connect(real_driver, SIGNAL(sig_log(int, int, QString)), this, SLOT(do_send_log(int, int, QString)), QObject::QueuedConnection); | |
62 | 98 | } |
63 | - int get_latency() | |
99 | + virtual void release_driver() | |
64 | 100 | { |
65 | - return m_latency_ms.load(); | |
66 | 101 | } |
67 | - int get_channels() | |
102 | + | |
103 | + int64_t update_sound(void* datasrc, int samples); | |
104 | + | |
105 | + std::shared_ptr<QIODevice> set_io_device(QIODevice *p); | |
106 | + std::shared_ptr<QIODevice> set_io_device(std::shared_ptr<QIODevice> ps); | |
107 | + std::shared_ptr<QIODevice> get_io_device() | |
68 | 108 | { |
69 | - return m_channels.load(); | |
109 | + return m_fileio; | |
70 | 110 | } |
71 | - virtual bool real_reconfig_sound(int& rate,int& channels,int& latency_ms) | |
111 | + bool is_io_device_exists(); | |
112 | + | |
113 | + virtual uint64_t wrote_data_to() | |
72 | 114 | { |
73 | - return true; | |
115 | + return 0; | |
74 | 116 | } |
75 | - template <class... Args> | |
76 | - bool debug_log(Args... args) | |
117 | + virtual int64_t driver_elapsed_usec() | |
77 | 118 | { |
78 | - _TCHAR buf[512] = {0}; | |
79 | - my_sprintf_s(buf, sizeof(buf) - 1, args); | |
80 | - return do_send_log(m_loglevel.load(), m_logdomain.load(), (const _TCHAR*)buf, (sizeof(buf) / sizeof(_TCHAR)) - 1); | |
119 | + return 0; | |
81 | 120 | } |
82 | - template <class... Args> | |
83 | - bool debug_log(imt level, int domain, Args... args) | |
121 | + virtual int64_t driver_processed_usec() | |
84 | 122 | { |
85 | - _TCHAR buf[512] = {0}; | |
86 | - my_sprintf_s(buf, sizeof(buf) - 1, args); | |
87 | - return do_send_log(level, domain, (const _TCHAR*)buf, (sizeof(buf) / sizeof(_TCHAR)) - 1); | |
123 | + return 0; | |
88 | 124 | } |
89 | 125 | bool config_ok() |
90 | 126 | { |
91 | 127 | return m_config_ok.load(); |
92 | 128 | } |
129 | + | |
130 | + int64_t get_buffer_bytes(); | |
131 | + int64_t get_chunk_bytes(); | |
132 | + int get_latency_ms(); | |
133 | + int get_channels(); | |
134 | + int get_sample_rate(); | |
135 | + size_t get_word_size(); | |
136 | + void get_buffer_parameters(int& channels, int& rate, int& latency_ms, | |
137 | + size_t& word_size, int& chunk_bytes, int& buffer_bytes); | |
138 | + virtual int64_t get_bytes_available(); | |
139 | + virtual int64_t get_bytes_left(); | |
140 | + | |
141 | + virtual SOUND_OUTPUT_MODULE_BASE* get_real_driver() | |
142 | + { | |
143 | + return dynamic_cast<SOUND_OUTPUT_MODULE_BASE>this; | |
144 | + } | |
145 | + | |
93 | 146 | virtual std::list<std::string> get_sound_devices_list() |
94 | 147 | { |
95 | 148 | static std::list<std::string> dummy_list; |
96 | 149 | return dummy_list; |
97 | 150 | } |
98 | - const _TCHAR* get_current_device_name() | |
151 | + | |
152 | + virtual const _TCHAR* get_sound_device_name(int num) | |
99 | 153 | { |
100 | - return (const _TCHAR*)(m_device_name.c_str()); | |
154 | + return (const _TCHAR*)nullptr; | |
101 | 155 | } |
156 | + virtual const _TCHAR* get_current_device_name() | |
157 | + { | |
158 | + return (const _TCHAR*)(_T("Empty")); | |
159 | + } | |
160 | + | |
102 | 161 | virtual void set_logger(const std::shared_ptr<CSP_Logger> logger); |
103 | 162 | virtual void set_system_flags(const std::shared_ptr<USING_FLAGS> p); |
104 | - | |
105 | -public slot: | |
106 | - bool update_rate(int& rate) | |
163 | + void* get_extra_config_ptr() | |
107 | 164 | { |
108 | - return reconfig_sound(rate, m_channels, m_latency_ms); | |
165 | + return m_extconfig_ptr.load(); | |
109 | 166 | } |
110 | - bool update_latency(int& latency_ms) | |
167 | + int get_extra_config_bytes() | |
111 | 168 | { |
112 | - return reconfig_sound(m_rate, m_channels, latency_ms); | |
169 | + return m_extconfig_bytes.load(); | |
113 | 170 | } |
114 | - bool update_channels(int& channels) | |
171 | + virtual bool set_extra_config(void* p, int bytes); | |
172 | + virtual bool modify_extra_config(void* p, int& bytes); | |
173 | +public slot: | |
174 | + virtual void update_config() {} | |
175 | + virtual void update_extra_config() {} | |
176 | + | |
177 | + bool start(); | |
178 | + bool pause(); | |
179 | + bool resume(); | |
180 | + bool stop(); | |
181 | + bool discard(); | |
182 | + | |
183 | + virtual void reset_to_defalut() {} | |
184 | + virtual void set_volume(double level) {} | |
185 | + virtual bool is_running_sound() | |
115 | 186 | { |
116 | - return reconfig_sound(rate, m_channels, m_latency_ms); | |
187 | + return true; | |
117 | 188 | } |
118 | - bool reconfig_sound(int& rate, int& channels, int& latency_ms) | |
189 | + bool update_rate(int rate) | |
119 | 190 | { |
120 | - // ToDo | |
121 | - std::lock_guard<std::recursive_mutex> locker(m_locker); | |
122 | - if((rate != m_rate.load()) || (channels != m_channels.load()) || (latency_ms != m_latency_ms.load())) { | |
123 | - if(real_reconfig_sound(rate, channels, latency_ms)) { | |
124 | - m_rate = rate; | |
125 | - m_channels = channels; | |
126 | - m_latency_ms = latency_ms; | |
127 | - m_config_ok = true; | |
128 | - return true; | |
129 | - } | |
130 | - } | |
131 | - return false; | |
191 | + return reconfig_sound(rate, m_channels); | |
132 | 192 | } |
133 | - void request_to_release(); | |
134 | - virtual const std::string set_device_sound(const _TCHAR* driver_name, int& rate,int& channels,int& latency_ms) | |
193 | + bool update_channels(int channels) | |
135 | 194 | { |
136 | - return std::string(_T("Empty Device")); | |
195 | + return reconfig_sound(m_rate, channels); | |
137 | 196 | } |
138 | - virtual bool do_send_log(imt level, int domain, const _TCHAR* str, int maxlen); | |
139 | - virtual void do_set_device_by_name(QString) {}; | |
140 | - virtual void do_set_device_by_number(int) {}; | |
141 | - virtual void do_set_device_from_sender_object(void) {}; | |
142 | - | |
143 | - virtual void initialize_sound(int rate, int samples, int* presented_rate, int* presented_samples) {} | |
144 | - virtual void release_sound() {} | |
145 | - | |
146 | - virtual void update_sound(int* extra_frames) {} | |
147 | - | |
148 | - virtual void mute_sound() {} | |
149 | - virtual void stop_sound() {} | |
150 | - | |
151 | - // *PURE* SLOTS | |
152 | - virtual void do_start_recording_sound() {} | |
153 | - virtual void do_stop_recording_sound() {} | |
154 | - virtual void do_restart_recording_sound() {} | |
155 | - virtual void do_request_capture_sound(int ch) {} | |
197 | + bool update_latency(int latency_ms, bool fortce = false); | |
198 | + bool reconfig_sound(int rate, int channels); | |
199 | + void request_to_release(); | |
156 | 200 | |
157 | - virtual void set_osd(OSD_BASE* p); | |
158 | - virtual void update_extra_config(void* p); | |
159 | - virtual int result_opening_external_file(); | |
201 | + virtual bool do_send_log(int level, int domain, QString _str); | |
202 | + virtual bool do_send_log(int level, int domain, const _TCHAR* _str, int maxlen); | |
203 | + virtual bool do_send_log(const _TCHAR* str, int maxlen) | |
160 | 204 | { |
161 | - return 0; | |
205 | + do_send_log(m_loglevel.load(), m_logdomain.load(), _str, maxlen); | |
162 | 206 | } |
163 | - virtual int64_t wrote_data_to() | |
207 | + virtual bool do_send_log(const QString _str) | |
164 | 208 | { |
165 | - return 0; | |
209 | + do_send_log(m_loglevel.load(), m_logdomain.load(), _str); | |
166 | 210 | } |
167 | - virtual bool result_closing_external_file() | |
211 | + | |
212 | + virtual void do_set_device_by_name(QString name) {}; | |
213 | + virtual void do_set_device_by_name(const _TCHAR *name) | |
168 | 214 | { |
169 | - return true; | |
215 | + if(name != nullptr) { | |
216 | + do_set_device_by_name(QString::fromUtf8(name)); | |
217 | + } | |
170 | 218 | } |
219 | + virtual void do_set_device_by_name(const _TCHAR *name, int maxlen) | |
220 | + { | |
221 | + if((name != nullptr) && (maxlen > 0)) { | |
222 | + do_set_device_by_name(QString::fromUtf8(name, maxlen)); | |
223 | + } | |
224 | + } | |
225 | + virtual void do_set_device_by_number(int) {}; | |
226 | + | |
227 | + // This set device by device-name having QAction (as QObject). | |
228 | + virtual void do_set_device_by_name(void); | |
229 | + virtual void do_set_device_by_number(void); | |
230 | + | |
231 | + // From real driver: notify to update sound devices list. | |
232 | + virtual void do_update_device_list() {} | |
233 | + | |
234 | + virtual void set_osd(OSD_BASE* p); | |
235 | + | |
171 | 236 | signals: |
172 | 237 | // loglevel, logdomain, message |
173 | 238 | void sig_send_log(int, int, QString); |
174 | 239 | // rate, channels, path |
175 | 240 | void sig_req_open_sound(int, int, QString); |
241 | + // | |
242 | + void sig_start_audio(); | |
243 | + void sig_pause_audio(); | |
244 | + void sig_resume_audio(); | |
245 | + void sig_close_audio(); | |
246 | + void sig_discard_audio(); | |
176 | 247 | // |
177 | - void sig_req_close_sound(); | |
178 | - // samples, channel, data | |
179 | - void sig_send_output_sound_data(int64_t, int, int16_t[]); | |
180 | - // update device list for ui | |
181 | - void sig_clear_sound_device(); | |
182 | - // add/update device, number and name. If number < 0 append. | |
183 | - void sig_add_sound_device_name(int, QString); | |
184 | - // Send current device number and name to UI. | |
185 | - void sig_send_current_device_description(int, QString); | |
186 | - // Notify updating devices list to UI. size, current_device_number, need_to_reconfig | |
187 | - void sig_notify_update_devices_list(int, int, bool); | |
188 | - // notify device changed status, true = success. | |
189 | - void sig_notify_changed_device_status(bool); | |
190 | 248 | // notify completed to release sound driver. |
191 | - void sig_released(bool); | |
249 | + void sig_released(bool); | |
250 | + // To UI: notify reset sound device list. | |
251 | + void sig_reset_sound_device_list(); | |
252 | + // To UI: notify update sound device list #arg1 to #arg2. | |
253 | + void sig_set_sound_device(int, QString); | |
254 | + // To UI: notify adding sound device list #arg1. | |
255 | + void sig_add_sound_device(QString); | |
192 | 256 | }; |
193 | 257 | |
194 | 258 | QT_END_NAMESPACE |