Common Source Code Project for Qt (a.k.a for FM-7).
Revision | a15cc60139820146a18cb693682dab696754b747 (tree) |
---|---|
Zeit | 2022-10-18 22:20:28 |
Autor | K.Ohta <whatisthis.sowhat@gmai...> |
Commiter | K.Ohta |
[OSD][SOUND][Qt] QT_MULTIMEDIA: Reduce jitter and delay.
@@ -295,7 +295,7 @@ void OSD_BASE::initialize_sound(int rate, int samples, int* presented_rate, int* | ||
295 | 295 | sound_buf_ptr = NULL; |
296 | 296 | sound_initialized = false; |
297 | 297 | // initialize direct sound |
298 | - | |
298 | + | |
299 | 299 | snd_total_volume = 127; |
300 | 300 | |
301 | 301 | snddata.sound_buf_ptr = (uint8_t**)(&sound_buf_ptr); |
@@ -445,10 +445,11 @@ void OSD_BASE::update_sound(int* extra_frames) | ||
445 | 445 | *extra_frames = 0; |
446 | 446 | |
447 | 447 | now_mute = false; |
448 | - if(sound_ok) { | |
448 | + if(sound_initialized) { | |
449 | 449 | // Get sound driver |
450 | 450 | std::shared_ptr<SOUND_MODULE::OUTPUT::M_BASE>sound_drv = m_sound_driver; |
451 | 451 | if(sound_drv.get() == nullptr) { |
452 | + // ToDo: Fix delay. | |
452 | 453 | return; |
453 | 454 | } |
454 | 455 |
@@ -456,31 +457,32 @@ void OSD_BASE::update_sound(int* extra_frames) | ||
456 | 457 | // source (= by VM) rendering data. |
457 | 458 | int sound_samples = sound_drv->get_sample_count(); |
458 | 459 | // Check driver elapsed by real time. |
459 | - if(sound_started) { | |
460 | + if(sound_drv->is_driver_started()) { | |
460 | 461 | if(!(sound_drv->check_elapsed_to_render())) { |
461 | -#if 0 | |
462 | - | |
463 | - int now_mixed_ptr = 0; | |
464 | - if(vm == nullptr) { | |
465 | - return; | |
466 | - } | |
467 | - now_mixed_ptr = vm->get_sound_buffer_ptr(); | |
468 | - if(now_mixed_ptr < ((sound_samples * 100) / 100)) { | |
469 | - // Render even emulate 100% of latency. | |
470 | - return; | |
471 | - } | |
472 | -#else | |
473 | 462 | return; |
474 | -#endif | |
475 | 463 | } |
476 | - } else { | |
464 | + } else if(!(sound_ok) /*&& (sound_drv->config_ok())*/) { | |
477 | 465 | sound_drv->start(); |
478 | - sound_started = true; | |
479 | 466 | if(p_config != nullptr) { |
480 | 467 | sound_drv->set_volume((int)(p_config->general_sound_level)); |
481 | 468 | } |
482 | - sound_drv->update_render_point_usec(); | |
469 | + //sound_drv->update_render_point_usec(); | |
470 | + sound_ok = true; | |
471 | + return; | |
472 | + } else { | |
473 | +#if 0 | |
474 | + int now_mixed_ptr = 0; | |
475 | + if(vm == nullptr) { | |
476 | + return; | |
477 | + } | |
478 | + now_mixed_ptr = vm->get_sound_buffer_ptr(); | |
479 | + if(now_mixed_ptr < ((sound_samples * 100) / 100)) { | |
480 | + // Render even emulate 100% of latency. | |
481 | + return; | |
482 | + } | |
483 | +#else | |
483 | 484 | return; |
485 | +#endif | |
484 | 486 | } |
485 | 487 | int16_t* sound_buffer = (int16_t*)create_sound(extra_frames); |
486 | 488 | if(sound_buffer == nullptr) { |
@@ -513,17 +515,17 @@ void OSD_BASE::update_sound(int* extra_frames) | ||
513 | 515 | } |
514 | 516 | } |
515 | 517 | // ToDo: Convert sound format. |
516 | - if(!(sound_drv->check_enough_to_render())) { | |
518 | + if(sound_drv.get() != nullptr) { | |
519 | + if(!(sound_drv->check_enough_to_render())) { | |
517 | 520 | // Buffer underflow. |
518 | - sound_drv->discard(); | |
521 | + //sound_drv->discard(); | |
522 | + //sound_drv->update_render_point_usec(); | |
523 | + return; | |
524 | + } | |
525 | + int64_t _result = 0; | |
526 | + _result = sound_drv->update_sound((void*)sound_buffer, sound_samples); | |
519 | 527 | sound_drv->update_render_point_usec(); |
520 | - return; | |
521 | 528 | } |
522 | - int64_t _result = 0; | |
523 | - _result = sound_drv->update_sound((void*)sound_buffer, sound_samples); | |
524 | - //debug_log(CSP_LOG_DEBUG, CSP_LOG_TYPE_SOUND, | |
525 | - // _T("OSD::%s() : sound result=%d"), __func__, _result); | |
526 | - sound_drv->update_render_point_usec(); | |
527 | 529 | } |
528 | 530 | } |
529 | 531 |
@@ -552,7 +554,8 @@ void OSD_BASE::initialize_sound(int rate, int samples, int* presented_rate, int* | ||
552 | 554 | if(sound_drv.get() != nullptr) { |
553 | 555 | sound_drv->initialize_sound(rate, samples, presented_rate, presented_samples); |
554 | 556 | //sound_drv->update_render_point_usec(); |
555 | - sound_ok = true; | |
557 | + sound_initialized = true; | |
558 | + sound_ok = false; | |
556 | 559 | } |
557 | 560 | } |
558 | 561 | void OSD_BASE::release_sound() |
@@ -623,6 +626,8 @@ void OSD_BASE::stop_sound() | ||
623 | 626 | sound_drv->stop_sound(); |
624 | 627 | } |
625 | 628 | } |
629 | + sound_initialized = false; | |
630 | + sound_ok = false; | |
626 | 631 | } |
627 | 632 | |
628 | 633 | int OSD_BASE::get_sound_rate() |
@@ -368,10 +368,12 @@ void M_BASE::release_sound() | ||
368 | 368 | |
369 | 369 | bool M_BASE::check_elapsed_to_render() |
370 | 370 | { |
371 | - const int64_t sound_us_now = driver_elapsed_usec(); | |
372 | 371 | //const int64_t sound_us_now = driver_processed_usec(); |
373 | 372 | if(m_rate <= 0) return false; |
374 | - | |
373 | + if(!(is_driver_started())) { | |
374 | + return false; | |
375 | + } | |
376 | + const int64_t sound_us_now = driver_elapsed_usec(); | |
375 | 377 | const int64_t _period_usec = m_latency_ms * 1000; |
376 | 378 | int64_t _diff = sound_us_now - m_before_rendered; |
377 | 379 | if((_diff < 0) && ((INT64_MAX - m_before_rendered) <= _period_usec)) { |
@@ -384,9 +386,9 @@ bool M_BASE::check_elapsed_to_render() | ||
384 | 386 | if(_diff < (_period_usec - 2000)) { |
385 | 387 | return false; |
386 | 388 | } |
387 | - //if(_diff < _period_usec) { | |
388 | - // return false; | |
389 | - //} | |
389 | +// if(_diff < _period_usec) { | |
390 | +// return false; | |
391 | +// } | |
390 | 392 | return true; |
391 | 393 | } |
392 | 394 |
@@ -425,14 +427,17 @@ int64_t M_BASE::update_sound(void* datasrc, int samples) | ||
425 | 427 | std::shared_ptr<SOUND_BUFFER_QT>q = m_fileio; |
426 | 428 | //__debug_log_func(_T("SRC=%0llx samples=%d fileio=%0llx"), (uintptr_t)datasrc, samples, (uintptr_t)(q.get())); |
427 | 429 | if(q.get() == nullptr) return -1; |
428 | - | |
430 | + if(!(is_driver_started()) || !(q->isOpen())) { | |
431 | + return -1; | |
432 | + } | |
433 | + int64_t _result = -1; | |
429 | 434 | if(samples > 0) { |
430 | 435 | qint64 _size = (qint64)(samples * m_channels) * (qint64)m_wordsize; |
431 | - return (int64_t)q->write((const char *)datasrc, _size); | |
436 | + _result = (int64_t)q->write((const char *)datasrc, _size); | |
432 | 437 | } else if(samples < 0) { |
433 | - return (int64_t)q->write((const char *)datasrc, m_chunk_bytes); | |
438 | + _result = (int64_t)q->write((const char *)datasrc, m_chunk_bytes); | |
434 | 439 | } |
435 | - return -1; | |
440 | + return _result; | |
436 | 441 | } |
437 | 442 | |
438 | 443 |
@@ -119,12 +119,16 @@ void M_QT_MULTIMEDIA::set_audio_format(QAudioDevice dest_device, QAudioFormat& d | ||
119 | 119 | } else if(dest_device.maximumChannelCount() < _channels) { |
120 | 120 | _channels = dest_device.maximumChannelCount(); |
121 | 121 | } |
122 | - if(dest_device.minimumSampleRate() > rate) { | |
123 | - rate = dest_device.minimumSampleRate(); | |
124 | - } else if(dest_device.maximumSampleRate() < rate) { | |
125 | - rate = dest_device.maximumSampleRate(); | |
126 | - } | |
127 | - if((rate <= 0)) { | |
122 | + int _rate = rate; | |
123 | + if(dest_device.minimumSampleRate() > _rate) { | |
124 | + _rate = dest_device.minimumSampleRate(); | |
125 | + } else if(dest_device.maximumSampleRate() < _rate) { | |
126 | + _rate = dest_device.maximumSampleRate(); | |
127 | + } | |
128 | + //if(_rate > 0) { | |
129 | + rate = _rate; // Workaround 20221018 K.O | |
130 | + //} | |
131 | + if(_rate <= 0) { | |
128 | 132 | return; |
129 | 133 | } |
130 | 134 | if(_channels > 0) { |
@@ -343,11 +347,15 @@ QAudioDeviceInfo M_QT_MULTIMEDIA::get_device_by_name(QString driver_name) | ||
343 | 347 | |
344 | 348 | void M_QT_MULTIMEDIA::do_set_device_by_name(QString driver_name) |
345 | 349 | { |
350 | + if(m_device_name == driver_name.toLocal8Bit().toStdString()) { | |
351 | + return; | |
352 | + } | |
346 | 353 | #if QT_VERSION >= QT_VERSION_CHECK(6, 2, 0) |
347 | 354 | QAudioDevice dest_device = get_device_by_name(driver_name); |
348 | 355 | #elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
349 | 356 | QAudioDeviceInfo dest_device = get_device_by_name(driver_name); |
350 | 357 | #endif |
358 | + | |
351 | 359 | setup_device(dest_device, m_rate, m_channels, m_latency_ms, true); |
352 | 360 | } |
353 | 361 |
@@ -434,7 +442,12 @@ void M_QT_MULTIMEDIA::setup_device(QAudioDeviceInfo dest_device, int& rate,int& | ||
434 | 442 | #elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
435 | 443 | m_audioOutputSink.reset(new QAudioOutput(dest_device, desired, this)); |
436 | 444 | #endif |
445 | + do_discard_sound(); | |
446 | + m_prev_started = false; | |
447 | + m_before_rendered = 0; | |
448 | + | |
437 | 449 | if(m_audioOutputSink.get() != nullptr) { |
450 | + m_audioOutputSink->setBufferSize(m_chunk_bytes); | |
438 | 451 | connect(m_audioOutputSink.get(), SIGNAL(stateChanged(QAudio::State)), this, SLOT(driver_state_changed(QAudio::State))); |
439 | 452 | channels = m_audioOutputSink->format().channelCount(); |
440 | 453 | rate = m_audioOutputSink->format().sampleRate(); |
@@ -454,9 +467,7 @@ void M_QT_MULTIMEDIA::setup_device(QAudioDeviceInfo dest_device, int& rate,int& | ||
454 | 467 | } |
455 | 468 | |
456 | 469 | recalc_samples(rate, latency_ms, true, true); |
457 | - | |
458 | 470 | m_config_ok = (m_fileio.get() != nullptr); |
459 | - | |
460 | 471 | if(m_config_ok.load()) { |
461 | 472 | real_reconfig_sound(rate, channels, latency_ms); |
462 | 473 | } |
@@ -522,11 +533,11 @@ bool M_QT_MULTIMEDIA::real_reconfig_sound(int& rate,int& channels,int& latency_m | ||
522 | 533 | } |
523 | 534 | |
524 | 535 | int64_t _samples = (rate * latency_ms) / 1000; |
525 | - if((rate != m_rate) || (_samples != m_samples) || (m_latency_ms != latency_ms)) { | |
536 | +// if((rate != m_rate) || (_samples != m_samples) || (m_latency_ms != latency_ms)) { | |
526 | 537 | m_device_name = set_device_sound((const _TCHAR *)(m_device_name.c_str()), rate, channels, latency_ms); |
527 | 538 | __debug_log_func(_T("Returned Driver=\"%s\" rate=%dHz channles=%d latency=%dmSec"), m_device_name.c_str(), rate, channels, latency_ms); |
528 | 539 | //emit sig_set_sound_device(m_device_name); |
529 | - } | |
540 | +// } | |
530 | 541 | if((rate <= 0) || (latency_ms <= 0)) { |
531 | 542 | rate = 48000; |
532 | 543 | latency_ms = 100; |
@@ -544,11 +555,9 @@ bool M_QT_MULTIMEDIA::real_reconfig_sound(int& rate,int& channels,int& latency_m | ||
544 | 555 | void M_QT_MULTIMEDIA::release_sound() |
545 | 556 | { |
546 | 557 | // std::lock_guard<std::recursive_timed_mutex> locker(m_locker); |
547 | - | |
548 | - m_audioOutputSink->disconnect(); | |
549 | - | |
550 | 558 | if(m_audioOutputSink.get() != nullptr) { |
551 | 559 | m_audioOutputSink->stop(); |
560 | + m_audioOutputSink->disconnect(); | |
552 | 561 | } |
553 | 562 | m_audioOutputSink.reset(); |
554 | 563 |
@@ -569,14 +578,24 @@ void M_QT_MULTIMEDIA::do_sound_start() | ||
569 | 578 | #elif QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
570 | 579 | std::shared_ptr<QAudioOutput> p = m_audioOutputSink; |
571 | 580 | #endif |
572 | - if(m_driver_fileio.get() != nullptr) { | |
573 | - m_driver_fileio->reset(); | |
581 | + if(p.get() == nullptr) { | |
582 | + return; | |
574 | 583 | } |
575 | - if(p.get() != nullptr) { | |
576 | - p->start(m_driver_fileio.get()); | |
577 | - __debug_log_func("GO. fileio=%0llx", m_driver_fileio.get()); | |
584 | + if((p->state() != QAudio::StoppedState) && (m_prev_started)) { | |
585 | +// update_render_point_usec(); | |
586 | + return; | |
578 | 587 | } |
588 | + if(m_driver_fileio.get() == nullptr) { | |
589 | + //m_driver_fileio->reset(); | |
590 | + return; | |
591 | + } | |
592 | + m_driver_fileio->reset(); | |
593 | + p->setBufferSize(m_chunk_bytes); | |
594 | + p->start(m_driver_fileio.get()); | |
579 | 595 | update_render_point_usec(); |
596 | + __debug_log_func("GO. fileio=%0llx", m_driver_fileio.get()); | |
597 | + | |
598 | + //update_render_point_usec(); | |
580 | 599 | m_prev_started = true; |
581 | 600 | } |
582 | 601 |
@@ -591,7 +610,7 @@ void M_QT_MULTIMEDIA::do_sound_stop() | ||
591 | 610 | p->stop(); |
592 | 611 | } |
593 | 612 | do_discard_sound(); |
594 | - update_render_point_usec(); | |
613 | + m_before_rendered = 0; | |
595 | 614 | m_prev_started = false; |
596 | 615 | } |
597 | 616 |
@@ -641,6 +660,7 @@ int64_t M_QT_MULTIMEDIA::driver_elapsed_usec() | ||
641 | 660 | #endif |
642 | 661 | if(p.get() != nullptr) { |
643 | 662 | return (int64_t)(p->elapsedUSecs()); |
663 | + //return (int64_t)(p->processedUSecs()); | |
644 | 664 | } |
645 | 665 | return 0; |
646 | 666 | } |