Skip to content

fix(camera): warm up shutter audio on demand - #510

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:release/eaglefrom
Resurgamz:fix/shutter-sound-on-demand
Jul 30, 2026
Merged

fix(camera): warm up shutter audio on demand#510
deepin-bot[bot] merged 1 commit into
linuxdeepin:release/eaglefrom
Resurgamz:fix/shutter-sound-on-demand

Conversation

@Resurgamz

@Resurgamz Resurgamz commented Jul 30, 2026

Copy link
Copy Markdown

Summary

  • Replace Qt 5 QSound shutter playback with QSoundEffect.
  • Silently warm the audio stream before each shutter sound.
  • Stop the warmup stream before the real shutter playback to avoid continuous audio power usage.

Verification

  • cmake --build obj-x86_64-linux-gnu --target deepin-camera -- -j2

PMS: https://pms.uniontech.com/bug-view-369937.html

Summary by Sourcery

Replace the photo shutter sound implementation with a warmed-up QSoundEffect-based playback to reduce latency while avoiding continuous audio power usage.

New Features:

  • Introduce on-demand shutter sound warmup before photo capture using QSoundEffect.

Bug Fixes:

  • Prevent shutter sound latency and unintended continuous audio power usage by warming and stopping the audio stream before actual playback.

Enhancements:

  • Refine shutter sound lifecycle handling in videowidget, including status/playing change reactions and proper cleanup in the destructor.

Replace QSound with QSoundEffect and silently warm the audio stream before playing each shutter sound.\n\n使用 QSoundEffect 替换 QSound,并在播放快门音前静音预热音频流。\n\nLog: 修复快门音首声音量偏小的问题\nPMS: https://pms.uniontech.com/bug-view-369937.html\nInfluence: 空闲后的快门声音量正常,且不维持持续音频流。

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @Resurgamz, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@sourcery-ai

sourcery-ai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR replaces QSound with QSoundEffect for the camera shutter and adds an on‑demand warmup mechanism that silently primes the audio stream before playback while ensuring it is stopped and cleaned up correctly.

Sequence diagram for shutter sound warmup and playback

sequenceDiagram
    actor User
    participant videowidget
    participant QSoundEffect as m_takePicSound
    participant QTimer

    User->>videowidget: flash()
    videowidget->>videowidget: get_sound_of_takeing_photo()
    alt [sound enabled]
        videowidget->>videowidget: m_shutterSoundPending = true
        videowidget->>videowidget: startShutterSoundWarmup()
        opt [!m_shutterSoundWarming && status == Ready]
            videowidget->>m_takePicSound: setVolume(0.0)
            videowidget->>m_takePicSound: play()
        end
    end

    m_takePicSound-->>videowidget: playingChanged
    videowidget->>videowidget: onShutterSoundPlayingChanged()
    alt [m_shutterSoundWarming]
        alt [isPlaying]
            videowidget->>m_takePicSound: stop()
        else [stopped]
            videowidget->>videowidget: m_shutterSoundWarming = false
            videowidget->>m_takePicSound: setVolume(1.0)
            alt [m_shutterSoundPending && get_sound_of_takeing_photo()]
                videowidget->>videowidget: m_shutterSoundPending = false
                videowidget->>QTimer: singleShot(0)
                QTimer-->>videowidget: timeout lambda
                videowidget->>videowidget: get_sound_of_takeing_photo()
                alt [sound still enabled]
                    videowidget->>m_takePicSound: play()
                end
            else
                videowidget->>videowidget: m_shutterSoundPending = false
            end
        end
    end

    m_takePicSound-->>videowidget: statusChanged
    videowidget->>videowidget: onShutterSoundStatusChanged()
    alt [status == Error]
        videowidget->>videowidget: m_shutterSoundWarming = false
        videowidget->>videowidget: m_shutterSoundPending = false
        videowidget->>m_takePicSound: setVolume(1.0)
    else [m_shutterSoundPending]
        videowidget->>videowidget: startShutterSoundWarmup()
    end

    User->>videowidget: ~videowidget()
    videowidget->>m_takePicSound: stop()
    videowidget->>m_takePicSound: delete
Loading

File-Level Changes

Change Details Files
Replace legacy QSound shutter playback with QSoundEffect and wire up state-change handlers.
  • Swap m_takePicSound type from QSound to QSoundEffect and adjust member declaration accordingly
  • Initialize QSoundEffect with qrc source, loop count, and volume in the constructor
  • Connect QSoundEffect::playingChanged and QSoundEffect::statusChanged signals to new videowidget slots
src/src/videowidget.cpp
src/src/videowidget.h
Implement warmup lifecycle for the shutter sound, including pending-shot handling and error recovery.
  • Add startShutterSoundWarmup() that plays the shutter sound at zero volume when ready to prime the audio stream
  • Add onShutterSoundPlayingChanged() to stop warmup playback once started, restore volume, and immediately play the shutter sound if a shot is pending and sound is enabled
  • Add onShutterSoundStatusChanged() to clear warmup/pending flags on error and restart warmup when appropriate
src/src/videowidget.cpp
src/src/videowidget.h
Update flash logic to use the warmup mechanism and ensure proper teardown of the sound effect.
  • Change flash() to mark the shutter sound as pending and trigger the warmup instead of playing directly
  • Stop m_takePicSound before deleting it in the destructor and remove the duplicate delete block to avoid double-free
src/src/videowidget.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:85分 - ■ 【总体评价】 > 代码通过引入预热机制解决了QSoundEffect首次播放延迟问题,状态管理逻辑清晰且修复了析构时的重复删除问题。 > 逻辑正确且修复了内存释放隐患,但因预热机制中存在轻微的竞态条件和状态机复杂度扣15分。 - ■ 【详细分析】 > > - 1.语法逻辑(基本正确)✓ > > 代码将QSound替换为QSoundEffect,并引入了预热机制。在`startShutterSoundWarmup`中检查`status() != QSoundEffect::Ready`避免无效播放,在`onShutterSoundPlayingChanged`中正确处理了播放状态的切换。析构函数中修复了原代码对`m_takePicSound`的重复`delete`问题,改为先`stop()`再`delete`。 > > 潜在问题:在`onShutterSoundPlayingChanged`中,当`isPlaying()`为true时调用`stop()`并直接`return`,此时`m_shutterSoundWarming`仍为`true`,依赖下一次`playingChanged`信号触发来重置状态。如果由于底层音频框架异常导致未能及时发出状态变更信号,可能导致`m_shutterSoundWarming`卡在`true`状态,后续拍照将无声。 > > 建议:在调用`stop()`后,可以结合`QTimer::singleShot`增加超时保护机制,确保在一定时间后强制重置`m_shutterSoundWarming`状态;或在调用`stop()`时直接重置部分状态标志。 - > - 2.代码质量(良好)✓ > > 代码结构清晰,新增的三个函数职责单一,命名符合规范。头文件中新增的成员变量使用了默认初始化(`= false`),提高了代码的健壮性。注释保持了一致性。 > > 潜在问题:`onShutterSoundPlayingChanged`和`onShutterSoundStatusChanged`中使用了魔法数字`0.0`和`1.0`表示音量,虽然在此上下文中容易理解,但不如使用常量或枚举清晰。 > > 建议:将音量值提取为命名常量,如`const qreal kShutterSoundVolumeMuted = 0.0;`和`const qreal kShutterSoundVolumeNormal = 1.0;`。 - > - 3.代码性能(无性能问题)✓ > > 预热机制通过静音播放解决了首次播放延迟,避免了在拍照瞬间因初始化导致的卡顿。使用`QTimer::singleShot(0, ...)`将实际播放操作放入事件循环,避免了在槽函数中直接执行可能导致的重入问题。 > > 建议:保持当前实现,无需额外优化。 - > - 4.代码安全(存在0个安全漏洞)✓ > > 漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个 > > 本次代码变更未引入任何安全漏洞,不存在命令注入、内存越界等风险。资源管理通过Qt的父子对象机制和显式`delete`结合,无内存泄漏风险。 > > - 建议:无需针对安全进行额外修复。 - ■ 【改进建议代码示例】
// videowidget.h
private:
    static constexpr qreal kShutterSoundVolumeMuted = 0.0;
    static constexpr qreal kShutterSoundVolumeNormal = 1.0;

// videowidget.cpp
void videowidget::onShutterSoundPlayingChanged()
{
    if (!m_shutterSoundWarming) {
        return;
    }

    if (m_takePicSound->isPlaying()) {
        m_takePicSound->stop();
        // 增加超时保护,防止状态卡死
        QTimer::singleShot(100, this, [this]() {
            if (m_shutterSoundWarming) {
                m_shutterSoundWarming = false;
                m_takePicSound->setVolume(kShutterSoundVolumeNormal);
            }
        });
        return;
    }

    m_shutterSoundWarming = false;
    m_takePicSound->setVolume(kShutterSoundVolumeNormal);
    if (m_shutterSoundPending && get_sound_of_takeing_photo()) {
        m_shutterSoundPending = false;
        QTimer::singleShot(0, this, [this] {
            if (get_sound_of_takeing_photo()) {
                m_takePicSound->play();
            }
        });
        return;
    }
    m_shutterSoundPending = false;
}

void videowidget::startShutterSoundWarmup()
{
    if (m_shutterSoundWarming || m_takePicSound->status() != QSoundEffect::Ready) {
        return;
    }

    m_shutterSoundWarming = true;
    m_takePicSound->setVolume(kShutterSoundVolumeMuted);
    m_takePicSound->play();
}

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: max-lvs, Resurgamz

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@Resurgamz

Copy link
Copy Markdown
Author

/merge

@deepin-bot
deepin-bot Bot merged commit 5a8a1a9 into linuxdeepin:release/eagle Jul 30, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants