<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: 宛涵</title>
    <description>The latest articles on DEV Community by 宛涵 (@hannes_wan).</description>
    <link>https://dev.to/hannes_wan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3998153%2Feefb549f-721a-4bb3-b28c-cbaa28b5b11d.jpg</url>
      <title>DEV Community: 宛涵</title>
      <link>https://dev.to/hannes_wan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hannes_wan"/>
    <language>en</language>
    <item>
      <title>A practical workflow for debugging flaky RTSP camera streams</title>
      <dc:creator>宛涵</dc:creator>
      <pubDate>Thu, 02 Jul 2026 06:04:24 +0000</pubDate>
      <link>https://dev.to/hannes_wan/a-practical-workflow-for-debugging-flaky-rtsp-camera-streams-46cj</link>
      <guid>https://dev.to/hannes_wan/a-practical-workflow-for-debugging-flaky-rtsp-camera-streams-46cj</guid>
      <description>&lt;p&gt;When an RTSP camera works 95% of the time and falls apart at the worst possible moment, you usually don't have a network problem — you have a &lt;em&gt;session&lt;/em&gt; problem. Here is the checklist I run before I touch the camera config or the VMS.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Confirm the session actually opens
&lt;/h2&gt;

&lt;p&gt;The first thing to check is whether &lt;code&gt;DESCRIBE&lt;/code&gt; returns a valid SDP. If the server replies with a 401 before SDP, your credential realm is wrong; if it returns SDP with &lt;code&gt;m=video 0&lt;/code&gt;, the server is advertising a track it cannot actually serve. Don't proceed until DESCRIBE returns something usable.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Read the SDP like a packet, not a string
&lt;/h2&gt;

&lt;p&gt;Two things matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;rtpmap&lt;/code&gt; and &lt;code&gt;fmtp&lt;/code&gt; lines tell you exactly what the encoder is sending. If the camera says H.264 &lt;a href="mailto:High@L4.1"&gt;High@L4.1&lt;/a&gt; but your decoder caps at Baseline, you will get a green wall, not an error.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;a=rtcp&lt;/code&gt; and &lt;code&gt;a=control&lt;/code&gt; attributes decide whether RTCP feedback and per-track SETUP will actually work. If &lt;code&gt;a=control&lt;/code&gt; is missing or duplicated, SETUP will hang forever even though DESCRIBE looked fine.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Watch the timing, not just the bytes
&lt;/h2&gt;

&lt;p&gt;RTP streams fail in two flavors: late packets and missing sequence numbers. With tcpdump and Wireshark I look at the inter-packet delta first — a 30 fps stream should sit near 33 ms, not 100 ms — and then at gaps in the sequence number. A consistent 33 ms with periodic sequence gaps usually means the camera is dropping at the encoder, not on the wire.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Inspect the interleaved binary
&lt;/h2&gt;

&lt;p&gt;For RTSP-over-TCP (the &lt;code&gt;RTP/AVP/TCP;interleaved=&lt;/code&gt; case), the failure mode is different. The interleaved channel can stop interleaving, and then your "RTSP" connection is silently just TCP. Open the TCP stream, count the &lt;code&gt;$&lt;/code&gt; framing bytes, and confirm the server is still emitting interleaved RTP and not just keepalive.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Decide what you actually need to repair
&lt;/h2&gt;

&lt;p&gt;Most of the time the diagnosis above points to one of three fixes: tweak the encoder profile, change the transport from UDP to TCP (or vice versa), or move the camera off a congested switch port. Sometimes the answer is that the recording you already have is fine but needs clean re-muxing.&lt;/p&gt;




&lt;p&gt;If you want a faster loop on steps 2–4, &lt;a href="https://hannes-software.com/rtsp-inspector/" rel="noopener noreferrer"&gt;RTSP Inspector&lt;/a&gt; is a local desktop tool I built that walks you through the same checklist with the actual SDP, RTP timing, and interleaved framing laid out next to each other. Disclosure: I am the author.&lt;/p&gt;

</description>
      <category>videostreaming</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Stop learning whole songs first: a local audio practice workflow for guitar and bass</title>
      <dc:creator>宛涵</dc:creator>
      <pubDate>Sat, 27 Jun 2026 01:55:17 +0000</pubDate>
      <link>https://dev.to/hannes_wan/stop-learning-whole-songs-first-a-local-audio-practice-workflow-for-guitar-and-bass-7e7</link>
      <guid>https://dev.to/hannes_wan/stop-learning-whole-songs-first-a-local-audio-practice-workflow-for-guitar-and-bass-7e7</guid>
      <description>&lt;h1&gt;
  
  
  Stop learning whole songs first: a local audio practice workflow for guitar and bass
&lt;/h1&gt;

&lt;p&gt;Most players do not get stuck because the next song is too hard.&lt;/p&gt;

&lt;p&gt;They get stuck because they keep trying to learn the whole recording at once: intro, verse, chorus, fill, solo, tone, timing, and memory all in the same practice pass. That feels productive for the first fifteen minutes, then it turns into scrolling tabs, restarting the track, and guessing where the problem actually is.&lt;/p&gt;

&lt;p&gt;A better workflow is smaller and more mechanical.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Pick one phrase, not one song
&lt;/h2&gt;

&lt;p&gt;Choose the smallest part that still feels musical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a two-bar riff&lt;/li&gt;
&lt;li&gt;one chord change&lt;/li&gt;
&lt;li&gt;one bass fill&lt;/li&gt;
&lt;li&gt;the first half of a lead phrase&lt;/li&gt;
&lt;li&gt;the transition into the chorus&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cannot hum it, count it, or tap the rhythm, it is too large for the first pass.&lt;/p&gt;

&lt;p&gt;The goal is not to "finish the song" today. The goal is to make one section boring.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Slow it down before you touch the instrument
&lt;/h2&gt;

&lt;p&gt;Slow practice only works if the loop is short enough.&lt;/p&gt;

&lt;p&gt;A useful starting point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;50-60% speed for a new phrase&lt;/li&gt;
&lt;li&gt;no pitch change if you are playing in the original key&lt;/li&gt;
&lt;li&gt;a loop that starts slightly before the mistake and ends slightly after it&lt;/li&gt;
&lt;li&gt;five clean repetitions before raising the tempo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not raise speed because you are bored. Raise speed when the timing survives boredom.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Separate sound, timing, and location
&lt;/h2&gt;

&lt;p&gt;For guitar and bass, three different things often get confused:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;what the phrase sounds like&lt;/li&gt;
&lt;li&gt;where the notes live on the fretboard&lt;/li&gt;
&lt;li&gt;how the rhythm sits against the track&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you try to solve all three at once, you usually memorize a hand shape without understanding the phrase.&lt;/p&gt;

&lt;p&gt;For guitar, name the key center and the chord tones under the phrase. Even basic intervals help: root, third, fifth, flat seventh. That turns a lick into something reusable.&lt;/p&gt;

&lt;p&gt;For bass, listen for the relationship to the kick and the chord movement before worrying about every ghost note. The low end often sounds busier than it is because the mix hides the attack.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Use tabs as a draft, not the source of truth
&lt;/h2&gt;

&lt;p&gt;Tabs are useful when they get you unstuck. They are dangerous when they replace listening.&lt;/p&gt;

&lt;p&gt;A good tab workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;listen first&lt;/li&gt;
&lt;li&gt;make a rough position guess&lt;/li&gt;
&lt;li&gt;check a tab or chart only where needed&lt;/li&gt;
&lt;li&gt;correct the fingering against the audio&lt;/li&gt;
&lt;li&gt;write down the version that actually works under your hand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For bass especially, the best chart is often not the prettiest one. It is the one you can play in time with the recording.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Keep the file local when possible
&lt;/h2&gt;

&lt;p&gt;For practice, local tools have a few boring but important advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no upload wait&lt;/li&gt;
&lt;li&gt;no subscription just to slow down a song&lt;/li&gt;
&lt;li&gt;no private lesson or rehearsal audio leaving your machine&lt;/li&gt;
&lt;li&gt;repeatable projects you can reopen tomorrow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That matters more than flashy features if you practice every day.&lt;/p&gt;

&lt;p&gt;Disclosure: I build local music practice tools for this kind of workflow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Session Craft is for slowing, looping, pitch shifting, chord timelines, and stem-focused practice from local audio: &lt;a href="https://hannes-software.com/session-craft/" rel="noopener noreferrer"&gt;https://hannes-software.com/session-craft/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fretboard Lab is for mapping chord tones, voicings, keys, and fretboard positions: &lt;a href="https://hannes-software.com/fretboard-lab/" rel="noopener noreferrer"&gt;https://hannes-software.com/fretboard-lab/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LowEnd Forge is for bass-first transcription: isolate the low end, draft four-string tab, edit it, and export a usable chart: &lt;a href="https://hannes-software.com/lowend-forge/" rel="noopener noreferrer"&gt;https://hannes-software.com/lowend-forge/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Community Free versions are enough to start. Do not pay for practice software until the workflow actually sticks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;Practice smaller sections than your ego wants.&lt;/p&gt;

&lt;p&gt;Slow the recording down.&lt;/p&gt;

&lt;p&gt;Loop until the mistake becomes boring.&lt;/p&gt;

&lt;p&gt;Learn why the notes work, not only where your fingers go.&lt;/p&gt;

&lt;p&gt;Then move to the next phrase.&lt;/p&gt;

</description>
      <category>music</category>
      <category>learning</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Bass transcription workflow: isolate the low end before drafting tab</title>
      <dc:creator>宛涵</dc:creator>
      <pubDate>Sat, 27 Jun 2026 01:53:56 +0000</pubDate>
      <link>https://dev.to/hannes_wan/bass-transcription-workflow-isolate-the-low-end-before-drafting-tab-4ep4</link>
      <guid>https://dev.to/hannes_wan/bass-transcription-workflow-isolate-the-low-end-before-drafting-tab-4ep4</guid>
      <description>&lt;h1&gt;
  
  
  Bass transcription workflow: isolate the low end before drafting tab
&lt;/h1&gt;

&lt;p&gt;Most "MP3 to bass tab" tools fail for the same reason: they treat the bass as a generic instrument and try to recognise every note in the mix at once. The result is a chart full of guesses that look like a bass line and play nothing like one.&lt;/p&gt;

&lt;p&gt;A usable bass transcription workflow does three things in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pull the bass role away from the rest of the mix.&lt;/li&gt;
&lt;li&gt;Trace the low-register line, not every pitched sound.&lt;/li&gt;
&lt;li&gt;Draft the chart against the waveform, so the bassist can correct decisions instead of fighting the tool.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This post walks through the steps in detail, with the failure modes that show up when each step is skipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why full-mix transcription is the wrong first step
&lt;/h2&gt;

&lt;p&gt;A bass part lives between roughly 40 Hz and 1 kHz:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;E1 (low E string)        ~41 Hz
A1                       ~55 Hz
D2                       ~73 Hz
G2                       ~98 Hz
upper harmonic focus    ~200-1000 Hz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A bass part sits behind kick and rhythm guitar, and often shares pitch classes with the piano's left hand. When a transcription engine runs across the whole mix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;kick transients register as low notes and pollute the note stream&lt;/li&gt;
&lt;li&gt;the bass guitar's body resonance is mistaken for sustained pitches&lt;/li&gt;
&lt;li&gt;pitch confidence drops every time the bass and another instrument share a note&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output looks complete. It is not playable. A bassist who prints it and brings it to rehearsal finds the rhythm is roughly right, the pitch classes are often wrong, and every "decision" the tool made is invisible.&lt;/p&gt;

&lt;p&gt;The fix is to narrow the source first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: isolate the bass role, not the bass frequency
&lt;/h2&gt;

&lt;p&gt;Bass isolation is not a single EQ move. Useful results come from a chain that mirrors how a bassist listens to a recording:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;start with a mid/side or center-channel pull so the bass-heavy centre content is reduced in the side image&lt;/li&gt;
&lt;li&gt;apply a high-pass above the bass register on the side image only, to kill vocals and guitars that pan wide&lt;/li&gt;
&lt;li&gt;run a low-pass around 1 kHz on the result so harmonics above the bass role drop out&lt;/li&gt;
&lt;li&gt;de-bleed the kick by sidechaining the bass to the kick, or by spectral subtraction if the bleed is consistent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The point is to keep the bass register but to remove the instruments that share it. If you only low-pass filter, you still have kick, rhythm guitar low end, and piano left hand polluting the line.&lt;/p&gt;

&lt;p&gt;A useful test: play the isolated signal alongside the original. You should hear the bass line move, with kick and guitar mostly gone, and the rest of the mix reduced but not silent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: trace the low-register line, not every note
&lt;/h2&gt;

&lt;p&gt;Once the source is clean, the transcription step needs to constrain the search to four strings and the bass register. Generic polyphonic transcription tries to label every pitched event, including harmonics that the bass plays briefly between notes. On a bass part, those are noise, not melody.&lt;/p&gt;

&lt;p&gt;A bass-focused trace should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;constrain the search to four strings at standard or alternate tuning&lt;/li&gt;
&lt;li&gt;prefer the lowest plausible note in any window where two pitches overlap&lt;/li&gt;
&lt;li&gt;track position changes across the neck, so a note on the A string at the 7th fret is recognised as E, not as D on the E string&lt;/li&gt;
&lt;li&gt;ignore sub-harmonic artefacts that come from the body resonance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the difference between a "tab that looks like bass" and a tab a bassist can play. If the chart shows two adjacent frets on the same string where the audio clearly walks, the trace followed the wrong string. If the chart shows notes that are physically impossible (B on the low B string followed by G on the D string at the same moment), the trace ignored position.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: draft against the waveform, not against the spectrogram
&lt;/h2&gt;

&lt;p&gt;A spectrogram is useful for picking out attack points. It is misleading for rhythm, because the strongest frequency on a bass note is often the fundamental, which arrives a few milliseconds after the attack.&lt;/p&gt;

&lt;p&gt;The reliable reference for a bass part is the waveform, with a vertical guide at each beat. The transcription should align note onsets to waveform peaks, not to spectrogram contours. When the chart shows a note that lands on a beat but the waveform peak is on the off-beat, the chart is wrong and the tool should let the bassist drag the note rather than offering another auto-fix.&lt;/p&gt;

&lt;p&gt;This is also where most auto-transcription tools lose trust. The user hears that something is off, cannot tell what, and starts over. A workflow that lets the bassist nudge individual notes against the waveform is faster and produces a chart that survives a second listen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure modes you can recognise early
&lt;/h2&gt;

&lt;p&gt;Once you know the failure modes, you can hear them in the chart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Every note is right but the rhythm is loose.&lt;/strong&gt; The trace followed the pitch class but not the attack. Re-align the onsets to waveform peaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes that should be on the same string jump to a higher string.&lt;/strong&gt; The position tracker lost the neck. Lower the search window or add a position hint at the start of the section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A long note shows up as multiple short notes.&lt;/strong&gt; The note tracker split on amplitude variation. Smooth the tracking window or merge notes within a phrase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ghost notes disappear.&lt;/strong&gt; Ghost notes are quiet and short. If the threshold is set for full-volume notes, ghost notes never enter the chart. Lower the threshold for unrecognised windows and add them back manually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The chart plays in time but sounds wrong.&lt;/strong&gt; The pitch classes are close, the rhythm is close, but it is not the bass line. This usually means the source was not isolated well enough and the trace is following another instrument. Go back to step 1.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to keep in the workflow
&lt;/h2&gt;

&lt;p&gt;A bass transcription workflow is not "run the auto-tab, clean up later". It is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Isolate the bass role, with the test of "play it next to the original".&lt;/li&gt;
&lt;li&gt;Trace the low-register line, constrained to four strings and the bass register.&lt;/li&gt;
&lt;li&gt;Draft against the waveform, so attacks line up with peaks.&lt;/li&gt;
&lt;li&gt;Edit the chart manually, with ghost notes, slides, and position changes the trace did not catch.&lt;/li&gt;
&lt;li&gt;Export a chart the player can take to the room.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each step is a chance to correct what the previous one guessed. Skipping any of them produces a chart that looks right and plays wrong, which is the main complaint people have with auto-tab tools.&lt;/p&gt;

&lt;p&gt;If you want a bass-first transcription workbench that runs the workflow above, LowEnd Forge is the local-first desktop tool I built for this. It isolates the bass role, drafts four-string tab, lets you correct notes against the waveform, and exports MIDI, MusicXML, and PDF. Community Free is free to evaluate; Professional is a one-time $19 licence, not a subscription.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LowEnd Forge: &lt;a href="https://hannes-software.com/lowend-forge" rel="noopener noreferrer"&gt;https://hannes-software.com/lowend-forge&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>music</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Dental practice management without the monthly cloud bill</title>
      <dc:creator>宛涵</dc:creator>
      <pubDate>Fri, 26 Jun 2026 01:52:26 +0000</pubDate>
      <link>https://dev.to/hannes_wan/dental-practice-management-without-the-monthly-cloud-bill-8i1</link>
      <guid>https://dev.to/hannes_wan/dental-practice-management-without-the-monthly-cloud-bill-8i1</guid>
      <description>&lt;p&gt;Are you running a small dental clinic and tired of paying $200–$500/month for cloud practice management software that breaks whenever the internet goes down?&lt;/p&gt;

&lt;p&gt;You are not alone. Every week on dental forums, someone asks: "Is there a dental software that does not require a subscription?" or "Our internet has been spotty — can we still run the front desk?"&lt;/p&gt;

&lt;p&gt;The short answer is yes. Desktop dental software still exists, and for a small clinic (1–5 chairs), it often works better than cloud-first suites.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a local clinic actually needs
&lt;/h2&gt;

&lt;p&gt;The daily workflow in a small dental practice is surprisingly consistent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Schedule appointments on a calendar&lt;/li&gt;
&lt;li&gt;Register new patients with medical history&lt;/li&gt;
&lt;li&gt;Record treatment notes per visit&lt;/li&gt;
&lt;li&gt;Chart procedures on a tooth diagram (FDI or universal)&lt;/li&gt;
&lt;li&gt;Generate invoices and record payments&lt;/li&gt;
&lt;li&gt;Print or email receipts&lt;/li&gt;
&lt;li&gt;Back up at the end of the day&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these require a live internet connection. They require a reliable database, a clear interface, and PDF export for when you do need to share records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why some clinics switch back from cloud
&lt;/h2&gt;

&lt;p&gt;The cloud practice management pitch sounds great on paper: access from anywhere, automatic updates, no IT maintenance. But the reality for small clinics includes:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Internet dependency.&lt;/strong&gt; When the ISP goes down (and it will), the front desk cannot check in patients, the dentist cannot pull yesterday's treatment notes, and billing stops.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pricing creep.&lt;/strong&gt; The $99/month starter tier quietly becomes $200+, then $350+, with features you never asked for bundled in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data migration lock-in.&lt;/strong&gt; Exporting years of patient records from a cloud system is often a paid professional service, not a built-in button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training churn.&lt;/strong&gt; Every major UI update forces retraining. Desktop software that stays stable saves hours per staff member.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to look for
&lt;/h2&gt;

&lt;p&gt;If you are evaluating practice management software for a small clinic, here is a pragmatic checklist:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Offline-first.&lt;/strong&gt; Can you open the schedule and patient records without internet?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local backups.&lt;/strong&gt; Can you copy the database to a USB drive or network folder at the end of the day?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-time purchase.&lt;/strong&gt; Is there a buy-once option, or is every feature behind a recurring paywall?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF export.&lt;/strong&gt; Can you share treatment records, invoices, and referrals without the recipient needing the same software?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GDPR / data control.&lt;/strong&gt; Do you know where your patient data lives, or is it mixed into a multi-tenant cloud database?&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A practical alternative
&lt;/h2&gt;

&lt;p&gt;I built &lt;a href="https://hannes-software.com/dental-ark/" rel="noopener noreferrer"&gt;Dental Ark&lt;/a&gt; because the small clinic workflow should not require a monthly SaaS subscription and a permanent internet connection. It is a local-first desktop application that runs on Windows and Linux, stores patient data on your own machine, and exports everything to PDF. There is a free community edition and a $119 professional license — one payment, not a subscription.&lt;/p&gt;

&lt;p&gt;The software handles appointments, patient records, treatment notes, FDI tooth charting, billing, follow-ups, PDF export, and manual backups. No internet required. No cloud dependency. No data leaving your clinic.&lt;/p&gt;

&lt;p&gt;If you are currently evaluating alternatives to Cloud 9, Curve, Dentrix, or Open Dental, or if you just want a fallback system for days when the cloud is down, the &lt;a href="https://hannes-software.com/dental-ark/" rel="noopener noreferrer"&gt;Dental Ark page&lt;/a&gt; has screenshots, a detailed feature list, and the community download link.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is not a sponsored post. I am the developer, and I build local-first desktop tools because I believe small clinics should own their data and control their software costs.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>practice</category>
    </item>
    <item>
      <title>USBPcap and usbmon debugging: what to collect before blaming firmware</title>
      <dc:creator>宛涵</dc:creator>
      <pubDate>Tue, 23 Jun 2026 07:16:50 +0000</pubDate>
      <link>https://dev.to/hannes_wan/usbpcap-and-usbmon-debugging-what-to-collect-before-blaming-firmware-3kci</link>
      <guid>https://dev.to/hannes_wan/usbpcap-and-usbmon-debugging-what-to-collect-before-blaming-firmware-3kci</guid>
      <description>&lt;p&gt;USB bugs are easy to describe badly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The device is not detected.
The HID report is wrong.
The endpoint stalls.
It works on one machine but not another.
The firmware team says the host is wrong.
The host team says the firmware is wrong.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fastest way out is to collect evidence at the USB transfer level.&lt;/p&gt;

&lt;p&gt;On Windows, that often means USBPcap. On Linux, that often means usbmon. The capture alone is only the beginning; the useful work is turning that capture into a readable explanation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the failure mode
&lt;/h2&gt;

&lt;p&gt;Before capturing, write down the exact failure.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Device never enumerates
Configuration is selected but interface does not start
HID input report length is unexpected
Bulk IN endpoint stops responding
CDC device opens but no data arrives
Mass Storage command times out
UVC camera exposes descriptors but preview fails
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different failures require different evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capture enumeration first
&lt;/h2&gt;

&lt;p&gt;If the device is not recognized correctly, capture from plug-in through configuration.&lt;/p&gt;

&lt;p&gt;Look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reset&lt;/li&gt;
&lt;li&gt;device descriptor request&lt;/li&gt;
&lt;li&gt;configuration descriptor request&lt;/li&gt;
&lt;li&gt;string descriptor requests&lt;/li&gt;
&lt;li&gt;set address&lt;/li&gt;
&lt;li&gt;set configuration&lt;/li&gt;
&lt;li&gt;interface and endpoint descriptors&lt;/li&gt;
&lt;li&gt;class-specific descriptors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enumeration bugs often hide in descriptors, not payload data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read descriptors like a contract
&lt;/h2&gt;

&lt;p&gt;Descriptors tell the host what the device claims to be.&lt;/p&gt;

&lt;p&gt;Check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bDeviceClass / bInterfaceClass
idVendor / idProduct
bcdUSB
configuration count
interface count
endpoint address and direction
endpoint transfer type
wMaxPacketSize
polling interval
HID report descriptor
CDC class descriptors
UVC class descriptors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the descriptor contract is wrong, the host may behave correctly while the product still fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separate control, interrupt, bulk, and isochronous traffic
&lt;/h2&gt;

&lt;p&gt;Not every transfer means the same thing.&lt;/p&gt;

&lt;p&gt;Control transfers often explain setup and class requests.&lt;/p&gt;

&lt;p&gt;Interrupt transfers often matter for HID devices.&lt;/p&gt;

&lt;p&gt;Bulk transfers often matter for CDC, storage, vendor protocols, and firmware update flows.&lt;/p&gt;

&lt;p&gt;Isochronous transfers often matter for cameras, audio, and real-time media.&lt;/p&gt;

&lt;p&gt;A readable timeline should keep these categories visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check setup packets before payloads
&lt;/h2&gt;

&lt;p&gt;For control transfers, inspect the setup packet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bmRequestType
bRequest
wValue
wIndex
wLength
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A single wrong &lt;code&gt;wIndex&lt;/code&gt; or request direction can explain a failure that looks like a payload problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compare good vs bad hosts
&lt;/h2&gt;

&lt;p&gt;If the device works on one machine and fails on another, capture both.&lt;/p&gt;

&lt;p&gt;Compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;descriptor requests&lt;/li&gt;
&lt;li&gt;selected configuration&lt;/li&gt;
&lt;li&gt;class driver behavior&lt;/li&gt;
&lt;li&gt;endpoint polling interval&lt;/li&gt;
&lt;li&gt;transfer sizes&lt;/li&gt;
&lt;li&gt;timeout patterns&lt;/li&gt;
&lt;li&gt;stall/clear-feature sequences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not assume the host with the failure is the only interesting one. The working host is your baseline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid overclaiming from software captures
&lt;/h2&gt;

&lt;p&gt;USBPcap and usbmon are software-side evidence. They are very useful, but they are not a replacement for a hardware analyzer when the question is electrical timing, signal integrity, low-level bus errors, or power behavior.&lt;/p&gt;

&lt;p&gt;Use software captures for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;enumeration logic&lt;/li&gt;
&lt;li&gt;descriptors&lt;/li&gt;
&lt;li&gt;class requests&lt;/li&gt;
&lt;li&gt;transfer sequence&lt;/li&gt;
&lt;li&gt;payload inspection&lt;/li&gt;
&lt;li&gt;host/device protocol behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use hardware tools when you need electrical truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to send to firmware or support
&lt;/h2&gt;

&lt;p&gt;A useful USB debugging handoff should include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OS and kernel/build version
Device VID/PID
Firmware version
Capture source: USBPcap or usbmon
Failure mode
Enumeration summary
Descriptor notes
Endpoint involved
Transfer timeline
Relevant setup packets
Payload examples if safe
What changed between good and bad runs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is much better than “USB does not work”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Bus Scope fits
&lt;/h2&gt;

&lt;p&gt;You can capture USB evidence with USBPcap, usbmon, Wireshark, and scripts. The hard part is making the session readable enough for firmware, hardware, and support teams to discuss the same evidence.&lt;/p&gt;

&lt;p&gt;I build &lt;a href="https://hannes-software.com/bus-scope/" rel="noopener noreferrer"&gt;Bus Scope&lt;/a&gt; for that workflow. It is a local desktop USB diagnostics workbench for inspecting USBPcap or usbmon evidence, descriptors, endpoints, HID reports, payloads, sessions, filters, and exportable support notes.&lt;/p&gt;

&lt;p&gt;It is not a professional hardware analyzer replacement for electrical timing or signal integrity. It is for daily software-side USB debugging and handoff.&lt;/p&gt;

&lt;p&gt;Disclosure: I build Bus Scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick checklist
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Define the exact failure mode
[ ] Capture from plug-in if enumeration matters
[ ] Save descriptors
[ ] Inspect setup packets
[ ] Separate transfer types
[ ] Compare good and bad hosts
[ ] Document OS, firmware, VID/PID
[ ] Export a readable handoff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to prepare a PCAP for vendor support without leaking the whole capture</title>
      <dc:creator>宛涵</dc:creator>
      <pubDate>Tue, 23 Jun 2026 07:02:13 +0000</pubDate>
      <link>https://dev.to/hannes_wan/how-to-prepare-a-pcap-for-vendor-support-without-leaking-the-whole-capture-c70</link>
      <guid>https://dev.to/hannes_wan/how-to-prepare-a-pcap-for-vendor-support-without-leaking-the-whole-capture-c70</guid>
      <description>&lt;p&gt;Packet captures are useful because they are specific. They are risky for the same reason.&lt;/p&gt;

&lt;p&gt;A raw PCAP can contain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;internal IP addresses&lt;/li&gt;
&lt;li&gt;hostnames&lt;/li&gt;
&lt;li&gt;credentials or tokens in cleartext protocols&lt;/li&gt;
&lt;li&gt;cookies&lt;/li&gt;
&lt;li&gt;DNS queries&lt;/li&gt;
&lt;li&gt;customer traffic unrelated to the bug&lt;/li&gt;
&lt;li&gt;proprietary endpoints&lt;/li&gt;
&lt;li&gt;timing information&lt;/li&gt;
&lt;li&gt;enough context to reveal network architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before sending a capture to a vendor, support team, customer, or public issue, treat it like evidence that needs minimization.&lt;/p&gt;

&lt;p&gt;The goal is not to make the file pretty. The goal is to preserve the packets needed to reproduce or explain the issue while removing everything that does not belong in the handoff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the question
&lt;/h2&gt;

&lt;p&gt;Do not edit a PCAP until you know what the receiver needs to answer.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Why does TLS negotiation fail after ServerHello?
Why does this device retransmit every request?
Why does the API return 400 only for this payload?
Why does the camera stream freeze after PLAY?
Why does DNS resolve differently on this subnet?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That question tells you which packets matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep a read-only original
&lt;/h2&gt;

&lt;p&gt;Always preserve the original capture.&lt;/p&gt;

&lt;p&gt;Recommended structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;case-1234/
  original/
    customer-capture-raw.pcapng
  working/
    filtered-draft.pcapng
  handoff/
    vendor-handoff-v1.pcapng
    notes.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Never overwrite the original file. If a later question appears, you may need to rebuild the handoff from the untouched source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reduce the time window
&lt;/h2&gt;

&lt;p&gt;The easiest safe reduction is time.&lt;/p&gt;

&lt;p&gt;If the failure happens between &lt;code&gt;10:42:13&lt;/code&gt; and &lt;code&gt;10:42:18&lt;/code&gt;, the vendor probably does not need a 45-minute capture.&lt;/p&gt;

&lt;p&gt;Keep:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a small lead-in before the failure&lt;/li&gt;
&lt;li&gt;the failure itself&lt;/li&gt;
&lt;li&gt;enough aftermath to show retries, resets, or recovery&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remove unrelated browsing, background sync, update checks, and other noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filter by conversation, not just protocol
&lt;/h2&gt;

&lt;p&gt;Protocol filters are often too broad.&lt;/p&gt;

&lt;p&gt;Instead of “all HTTP” or “all DNS”, narrow to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;client IP&lt;/li&gt;
&lt;li&gt;server IP&lt;/li&gt;
&lt;li&gt;port&lt;/li&gt;
&lt;li&gt;stream/conversation&lt;/li&gt;
&lt;li&gt;device MAC&lt;/li&gt;
&lt;li&gt;transaction ID&lt;/li&gt;
&lt;li&gt;request path if visible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A narrow conversation makes review faster and reduces accidental disclosure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redact identifiers deliberately
&lt;/h2&gt;

&lt;p&gt;Common fields to inspect before sharing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IP addresses
MAC addresses
Hostnames
DNS queries
HTTP headers
URLs and query strings
Cookies
Authorization headers
Email addresses
Usernames
Device serial numbers
Payload strings
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redaction should be intentional. Replacing every IP with nonsense can destroy routing evidence. Leaving every internal hostname can leak environment details.&lt;/p&gt;

&lt;p&gt;A good rule:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;preserve structure needed for diagnosis&lt;/li&gt;
&lt;li&gt;remove identities not needed for diagnosis&lt;/li&gt;
&lt;li&gt;document what changed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Repair checksums when rewriting
&lt;/h2&gt;

&lt;p&gt;If you modify packet bytes, addresses, or headers, checksums may no longer match.&lt;/p&gt;

&lt;p&gt;Some tools ignore bad checksums. Some analysis tools and test harnesses do not.&lt;/p&gt;

&lt;p&gt;After editing, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP header checksum&lt;/li&gt;
&lt;li&gt;TCP checksum&lt;/li&gt;
&lt;li&gt;UDP checksum&lt;/li&gt;
&lt;li&gt;transport length fields&lt;/li&gt;
&lt;li&gt;capture file format validity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the file is meant for replay, testing, or regression fixtures, checksum correctness matters more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a short handoff note
&lt;/h2&gt;

&lt;p&gt;Do not send a PCAP alone.&lt;/p&gt;

&lt;p&gt;Include a note like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Case: login request fails after TLS renegotiation
Original capture retained internally: yes
Shared file time window: 10:42:10-10:42:22 UTC
Included hosts: client 10.0.0.15, api.example.internal
Redactions: client IP anonymized, hostname shortened, cookies removed
Checksums repaired: yes
Expected symptom: server closes connection after packet 184
Question for vendor: is this close_notify behavior expected?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That note prevents the receiver from reverse-engineering your intent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate the final file
&lt;/h2&gt;

&lt;p&gt;Before sending:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Opens in Wireshark/tshark
[ ] Contains the failure
[ ] Does not contain unrelated traffic
[ ] Redactions are documented
[ ] Checksums are valid if needed
[ ] File size is reasonable
[ ] Receiver knows what question to answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where PCAP Surgery fits
&lt;/h2&gt;

&lt;p&gt;You can do parts of this with Wireshark, editcap, text notes, and scripts. The problem is that safe support handoff is a workflow, not one command.&lt;/p&gt;

&lt;p&gt;I build &lt;a href="https://hannes-software.com/pcap-surgery/" rel="noopener noreferrer"&gt;PCAP Surgery&lt;/a&gt; for that workflow: review, trim, redact, repair checksums, and export focused PCAP/PCAPNG files from a local desktop workbench.&lt;/p&gt;

&lt;p&gt;It is not a live packet sniffer, IDS, VPN, or traffic generator. It is for preparing packet evidence that can be safely handed to another person.&lt;/p&gt;

&lt;p&gt;Disclosure: I build PCAP Surgery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal handoff checklist
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Define the support question
[ ] Preserve the original capture
[ ] Trim the time window
[ ] Keep only relevant conversations
[ ] Redact sensitive identifiers
[ ] Repair checksums if rewriting
[ ] Export a focused PCAP/PCAPNG
[ ] Send a short note with the file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tutorial</category>
    </item>
    <item>
      <title>RTSP black screen troubleshooting: what to check when VLC works but your VMS does not</title>
      <dc:creator>宛涵</dc:creator>
      <pubDate>Tue, 23 Jun 2026 07:01:48 +0000</pubDate>
      <link>https://dev.to/hannes_wan/rtsp-black-screen-troubleshooting-what-to-check-when-vlc-works-but-your-vms-does-not-1pb9</link>
      <guid>https://dev.to/hannes_wan/rtsp-black-screen-troubleshooting-what-to-check-when-vlc-works-but-your-vms-does-not-1pb9</guid>
      <description>&lt;p&gt;An IP camera stream failure is rarely just “RTSP does not work”. The useful question is more specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did RTSP authentication succeed?&lt;/li&gt;
&lt;li&gt;Did DESCRIBE return the SDP you expected?&lt;/li&gt;
&lt;li&gt;Did SETUP choose TCP interleaved or UDP RTP?&lt;/li&gt;
&lt;li&gt;Is media arriving after PLAY?&lt;/li&gt;
&lt;li&gt;Are RTP sequence numbers continuous?&lt;/li&gt;
&lt;li&gt;Does the codec profile match what the client can decode?&lt;/li&gt;
&lt;li&gt;Is ONVIF handing the VMS a different URI than the one you tested in VLC?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a camera plays in VLC but not in an NVR/VMS, the failure is usually in the gap between “the stream exists” and “this client can negotiate, receive, and decode it reliably”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the exact URI
&lt;/h2&gt;

&lt;p&gt;Do not compare two different tests.&lt;/p&gt;

&lt;p&gt;Write down the full RTSP URL used by each client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rtsp://user:pass@camera.local:554/path
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check for differences in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;profile path&lt;/li&gt;
&lt;li&gt;channel number&lt;/li&gt;
&lt;li&gt;stream subtype&lt;/li&gt;
&lt;li&gt;query parameters&lt;/li&gt;
&lt;li&gt;username/password encoding&lt;/li&gt;
&lt;li&gt;transport settings&lt;/li&gt;
&lt;li&gt;ONVIF-generated URI vs manually copied URI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many cameras expose multiple profiles. VLC may be opening the main stream while the VMS is using a substream, or vice versa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the RTSP control flow
&lt;/h2&gt;

&lt;p&gt;A normal session usually looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OPTIONS
DESCRIBE
SETUP video
SETUP audio (optional)
PLAY
TEARDOWN
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful failure patterns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;401 loop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authentication is not being accepted. Check digest/basic auth, clock drift on some devices, special characters in passwords, and whether the VMS encodes credentials differently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DESCRIBE succeeds, SETUP fails
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client can read metadata but cannot negotiate media transport. Check UDP/TCP mode, client ports, firewall/NAT, and multicast settings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PLAY succeeds, black screen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The control session succeeded, but media or decoding failed. Now inspect RTP and codec details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the SDP instead of guessing
&lt;/h2&gt;

&lt;p&gt;The DESCRIBE response should return SDP similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=control:trackID=1
a=fmtp:96 packetization-mode=1; profile-level-id=...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;codec: H.264, H.265, MJPEG&lt;/li&gt;
&lt;li&gt;payload type&lt;/li&gt;
&lt;li&gt;control attribute&lt;/li&gt;
&lt;li&gt;SPS/PPS availability for H.264&lt;/li&gt;
&lt;li&gt;profile-level-id compatibility&lt;/li&gt;
&lt;li&gt;audio track that may confuse weaker clients&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A stream can be valid but still use a profile or packetization mode the receiving system handles poorly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify RTP actually arrives
&lt;/h2&gt;

&lt;p&gt;If RTSP SETUP selected UDP, confirm that RTP packets arrive on the negotiated ports.&lt;/p&gt;

&lt;p&gt;Symptoms of blocked media:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RTSP commands return 200 OK&lt;/li&gt;
&lt;li&gt;PLAY succeeds&lt;/li&gt;
&lt;li&gt;no RTP packets arrive&lt;/li&gt;
&lt;li&gt;no RTCP receiver reports&lt;/li&gt;
&lt;li&gt;client shows black screen or timeout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This often means firewall, NAT, VLAN, routing, or client port negotiation is the real issue.&lt;/p&gt;

&lt;p&gt;If TCP interleaved works but UDP does not, you have a transport path problem, not necessarily a camera problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspect RTP continuity
&lt;/h2&gt;

&lt;p&gt;When packets arrive but playback freezes or breaks, look for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sequence gaps&lt;/li&gt;
&lt;li&gt;timestamp jumps&lt;/li&gt;
&lt;li&gt;marker bit behavior&lt;/li&gt;
&lt;li&gt;payload type changes&lt;/li&gt;
&lt;li&gt;RTCP sender reports&lt;/li&gt;
&lt;li&gt;jitter patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few packet losses may be tolerable. Repeated gaps around keyframes can make a stream look like a decode failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  ONVIF handoff can hide the real URI
&lt;/h2&gt;

&lt;p&gt;Many VMS products discover cameras through ONVIF, then request stream URIs from the device.&lt;/p&gt;

&lt;p&gt;That URI may not match the one you tested manually.&lt;/p&gt;

&lt;p&gt;Compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ONVIF profile token&lt;/li&gt;
&lt;li&gt;returned media URI&lt;/li&gt;
&lt;li&gt;transport protocol requested by ONVIF client&lt;/li&gt;
&lt;li&gt;main/sub stream selection&lt;/li&gt;
&lt;li&gt;authentication behavior after handoff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If VLC uses a hand-written URI and the VMS uses an ONVIF URI, you have not tested the same thing yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to hand to support
&lt;/h2&gt;

&lt;p&gt;A useful report should include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Camera model / firmware
Client name and version
RTSP URL path (without password)
Transport mode: TCP or UDP
RTSP request/response summary
SDP video/audio details
RTP arrival status
Packet loss or sequence gap notes
Codec profile notes
Exact failure symptom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is much more actionable than “camera does not play”.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where RTSP Inspector fits
&lt;/h2&gt;

&lt;p&gt;You can do parts of this manually with VLC logs, Wireshark, ONVIF tools, and packet captures. The hard part is turning those pieces into a compact handoff that a camera vendor, installer, or VMS support team can understand.&lt;/p&gt;

&lt;p&gt;I build &lt;a href="https://hannes-software.com/rtsp-inspector/" rel="noopener noreferrer"&gt;RTSP Inspector&lt;/a&gt; for that workflow. It is a local desktop tool for RTSP, RTP, RTCP, SDP, ONVIF handoff, packet loss, and codec-readiness diagnostics. It is not a VMS, NVR, surveillance recorder, or media player; it is meant to explain why a stream does or does not work.&lt;/p&gt;

&lt;p&gt;A practical workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reproduce the failure with the same URI the client uses.&lt;/li&gt;
&lt;li&gt;Capture RTSP control messages and SDP.&lt;/li&gt;
&lt;li&gt;Confirm transport mode and media arrival.&lt;/li&gt;
&lt;li&gt;Inspect RTP/RTCP evidence.&lt;/li&gt;
&lt;li&gt;Export a report for support handoff.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Disclosure: I build RTSP Inspector.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick checklist
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ ] Same RTSP URI in both clients
[ ] Authentication result known
[ ] DESCRIBE response saved
[ ] SDP codec/profile inspected
[ ] SETUP transport mode known
[ ] RTP arrival confirmed
[ ] RTP sequence gaps checked
[ ] ONVIF media URI compared
[ ] Report prepared for support
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>debugging</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
