Conversation
There was a problem hiding this comment.
Pull request overview
Updates the MAUI samples to address an iOS camera video frame-order glitch and expands the Camera sample’s audio visualizer options, plus a small XAML namespace alias tweak and a repo ignore/config tweak.
Changes:
- iOS camera capture: remove
GetRawFullImagefallback to avoid out-of-order encoded frames. - Camera sample: add two new audio visualizers and update visualizer switching/UI wiring.
- Misc: rename XAML namespace prefix in SpaceShooter sample; add a Linguist-related line to ignore/config.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
src/Maui/Samples/Sandbox/Game/SpaceShooter.xaml |
Renames the XAML xmlns prefix used for MauiGame. |
src/Maui/Samples/Camera/Visualizers/AudioWaveformBars.cs |
Adds a new scrolling waveform bar visualizer implementation. |
src/Maui/Samples/Camera/Visualizers/AudioSoundBars.cs |
Adds a frequency-bin “sound bars” visualizer using Goertzel analysis. |
src/Maui/Samples/Camera/CameraTestPage.cs |
Adjusts visualizer button tap handler/text and resets visualizer on capture mode changes. |
src/Maui/Samples/Camera/CameraTestPage.AppCamera.cs |
Changes visualizer defaults and adds new visualizer options to the switcher. |
src/Maui/Addons/DrawnUi.Maui.Camera/Apple/SkiaCamera.Apple.cs |
Removes raw-full-image fallback to prevent video glitches from frame reordering. |
.gitignore |
Adds a linguist-vendored-style line (currently in the wrong config file). |
| Array.Copy(_barsBackBuffer, _barsFrontBuffer, BarCount); | ||
| Array.Copy(_peakHold, _peakHoldFront, BarCount); |
There was a problem hiding this comment.
The buffer handoff in Render copies from _barsBackBuffer/_peakHold into front arrays. Because AddSample can run concurrently, those arrays may be mutated while Array.Copy is in progress, producing torn/inconsistent frames. Consider using the same pointer-swap approach used by the other visualizers (swap front/back references for both bars and peak arrays), or guard copy/update with a lock.
| Array.Copy(_barsBackBuffer, _barsFrontBuffer, BarCount); | |
| Array.Copy(_peakHold, _peakHoldFront, BarCount); | |
| // Swap bar buffers atomically instead of copying to avoid torn frames | |
| var tmpBars = _barsFrontBuffer; | |
| _barsFrontBuffer = _barsBackBuffer; | |
| _barsBackBuffer = tmpBars; | |
| // Swap peak-hold buffers atomically as well | |
| var tmpPeaks = _peakHoldFront; | |
| _peakHoldFront = _peakHold; | |
| _peakHold = tmpPeaks; |
| float freq = (float)Math.Exp(logMin + t * (logMax - logMin)); | ||
| _goertzelFreqs[i] = freq; | ||
|
|
||
| // Goertzel: k = round(N * freq / sampleRate) |
There was a problem hiding this comment.
The Goertzel coefficient comment says k = round(N * freq / sampleRate), but the implementation uses a non-rounded (fractional) k. Either update the comment to match the actual approach, or apply rounding so the computed coefficient matches the documented algorithm.
| // Goertzel: k = round(N * freq / sampleRate) | |
| // Goertzel (fractional bin): k = N * freq / sampleRate |
| .ObserveProperty(CameraControl, nameof(CameraControl.CaptureMode), me => | ||
| { | ||
| me.IsVisible = CameraControl.CaptureMode == CaptureModeType.Video; | ||
| CameraControl.SwitchVisualizer(0); | ||
| //me.IsVisible = CameraControl.CaptureMode == CaptureModeType.Video; | ||
| }), |
There was a problem hiding this comment.
This CaptureMode observer now contains a commented-out visibility assignment and does not otherwise use the me parameter, which leaves dead code and an unused lambda parameter. Either restore the visibility logic, remove the observer entirely, or change the lambda parameter to _ and delete the commented line to keep the UI code clean.
|
|
||
| var old = _audioVisualizer; | ||
| bool useGain = true; | ||
| bool useGain = true; | ||
|
|
||
| switch (_visualizerIndex) |
There was a problem hiding this comment.
SwitchVisualizer can set _visualizerIndex to 7 (it increments through 0..8) but the switch has no case 7 and no default. In that situation _audioVisualizer remains pointing to the old instance, but old is still disposed at the end of the method, leaving _audioVisualizer referencing a disposed object (subsequent AddSample/Render calls may fail or behave incorrectly). Add a case 7 (or change the wrap limit) and/or add a default that assigns a new visualizer/null before disposing the old one.
No description provided.