Testing and release evidence

Align AudioRecord Frame Timestamps with PCM Chunks

Distinguish capture frame/time anchors from application read coordinates and permit chunk-time estimates only with a verified common origin.

Review status: Fact and editorial QA complete; owner review pending · 2026-10-08 · Fact IDs: ANDROID-AUDIO-01, ANDROID-TIMEBASE-2026-10, COVE-ASR-02, BENCHMARK-01, ANDROID-AUDIO-TIMESTAMP-2026-10

Direct answer

A capture timestamp and a buffer boundary describe different events. AudioRecord.getTimestamp returns an AudioTimestamp representing frame-delivery information at the earliest point available in the capture pipeline. AudioTimestamp.framePosition is a frame position relative to an assumed stream; nanoTime is the estimated capture time for that frame in the selected timebase. It is not defined as the end time of the most recently returned read buffer, so attaching it directly to a chunk without a frame-coordinate relation can shift every segment. AudioRecord.getTimestamp is API 24 and may return ERROR_INVALID_OPERATION when a timestamp is unavailable; update anchors only on success. AudioTimestamp.framePosition/nanoTime fields date from API 19, while MONOTONIC/BOOTTIME selection is API 24. Android maps those bases to System.nanoTime and elapsedRealtimeNanos, respectively. startRecording after stop resets the frame count; start a new epoch then. Record route or format changes, but do not assume they reset the counter. Read overloads return bytes, shorts, or floats, not frame counts. Convert successful data using the configured encoding and channel count; record incomplete tails or errors instead of dropping them silently. Maintain cumulative app-read frame ranges per chunk. A frame contains one sample per configured channel, but this app coordinate is not automatically AudioTimestamp's capture coordinate. A local time estimate is valid only after a capture-coordinate association is verified. Given a successful timestamp anchor (P, T), a chunk frame coordinate q that is proven to use the same capture origin, one uninterrupted recorder epoch, a matching clock base, and a stable sample rate R, the local estimate is t_est = T + (q - P) * 1e9 / R. This is a derived estimate, not an accuracy guarantee. If the first accepted read does not have a verified offset to capture framePosition, retain q and t_est as unknown instead of assuming the first read starts at frame zero. Timestamp/read deltas are diagnostic only when mapping and tolerance are known. Capture buffering, delayed reads, discarded data, and transforms can cause differences; one poll does not identify the cause. Compare repeated successful anchors with accepted read counts, return codes, route/recorder events, and controlled discontinuities. Distinguish scheduler delay, short read, route interruption, app discard, and unknown mismatch. Keep input-frame and transformed-output coordinates separate. Use two fixture tiers: pure PCM plus synthetic (P,T)/read ranges tests arithmetic only. A real-mic pulse replay can test capture, but its source-file frame label is not AudioRecord.framePosition; record the captured marker, route, method, and uncertainty. Use only a separately verified read-origin offset, never the nearest poll by default. If origin cannot be verified, timing stays unknown. Do not log real audio. COVE-ASR-02 describes sequential segmenting/merge, not timestamp support; no Cove implementation or device result is claimed.

A transcript segment needs a defensible media offset

An Android developer splits a live AudioRecord capture into PCM chunks for speech processing and later needs each transcript segment to point back to its approximate location in the recording. One test shows a time gap after a short read, but the app has only a display duration and does not know whether capture frames were delayed, dropped, or merely read later.

Decision

Pair successful AudioTimestamp anchors with a separately counted app-read frame timeline only when their origin, epoch, sample rate, and timebase have been verified. Treat unproven offsets as unknown and keep transform output frames separate.

Expected outcome

The report can map tested chunks to a bounded capture-time estimate or identify why mapping is unavailable. It does not turn a mismatch into proof of dropped audio or a timestamp-accuracy claim.

Evidence to collect

The claim becomes reviewable only when the following evidence is attached to the same artifact and test run:

  • Successful frame/time anchors with epoch and clock base
  • Read-overload units and separate chunk frame ranges
  • Controlled origin mapping, reset and unknown-offset fixtures

A release claim is valid only for the recorded configuration and acceptance set. Generalization requires additional records.

Implementation workflow

  1. Define the timestamp question and epoch. Record purpose, recorder ID, start/stop events, API level, sample format/channels, and the chosen MONOTONIC or BOOTTIME base. Create a new epoch only after a counter reset; log route/format changes without assuming reset.
  2. Capture only successful timestamp anchors. Poll getTimestamp at known points and store status, framePosition, nanoTime, and timebase together. Update the anchor only on SUCCESS; a failed query means unavailable, not permission to reuse stale fields as current time.
  3. Count frames from successful reads. Record each read overload and unit: bytes, shorts, or floats. Convert successful counts to complete frames using configured encoding/channels; mark short reads, errors, or incomplete tails. Keep cumulative app-read ranges separate from capture framePosition.
  4. Prove the read-to-capture offset before estimating. Establish an association between app frame coordinate q and capture position P for the same recorder epoch, stable sample rate, and clock base. Do not use the nearest timestamp poll as an unmeasured origin. Only then may t_est = T + (q - P) * 1e9 / R be used locally; otherwise keep mapping unknown.
  5. Investigate discontinuities with independent evidence. Compare repeated successful anchors with accepted read frames under a declared tolerance. Correlate mismatches with read results, route events, restart, resampling, and deliberate discards. One mismatch does not prove loss or identify its cause.
  6. Validate fixture tiers and privacy. Use two tiers: pure PCM plus synthetic P/T and read ranges tests arithmetic only. For real-mic pulse playback, record the captured marker, route, method, and uncertainty; source-file frame labels are not capture framePosition. Without verified origin, mark unknown. Never log real PCM or transcripts.

Keep each transition observable. A failure should identify the stage, artifact, runtime, and recovery action without logging private user content.

Acceptance criteria

  • Each anchor records AudioRecord session epoch, getTimestamp status, framePosition, nanoTime, selected timebase, and sample-format context; failed queries never reuse stale timestamp fields. Epochs change only on verified counter resets, while route/format changes are logged separately.
  • Successful read counts are converted from their actual byte/short/float units to complete frames using the configured format; app-read frame indices remain separate from capture framePosition until an offset is verified.
  • Any frame-to-time formula is limited to a verified common capture origin, epoch, stable rate, and matching clock domain; otherwise the time mapping is unknown.
  • A pure PCM/synthetic tuple test is arithmetic-only; source-file frame labels are not hardware capture positions. Real-mic mapping records its captured marker, route, method, and uncertainty, and remains unknown without verified origin evidence. A timestamp/read delta is not called a dropped-frame count without independent evidence.

Decision table

DimensionChoice or evidenceHow to interpret it
Task duration clockMonotonic or boottime endpoints for a named elapsed intervalAnswers how much time passed; it does not locate an individual sample frame in the capture stream.
AudioTimestamp anchorA successful framePosition/nanoTime pair in one capture epochAssociates an estimated capture time with a frame coordinate; it is not a read-buffer boundary or exact device-accuracy promise.
App-read chunk indexCumulative frames derived from successful AudioRecord read countsDescribes data delivered to the application; buffering or discarded data can make its origin differ from capture framePosition.
Transcription segment orderSequential chunk IDs and merged text resultsPreserves processing order but does not by itself retain source-time offsets.

Failure patterns to prevent

  • Attaching the latest timestamp to a read-buffer boundary
  • Calling a timestamp/read mismatch a dropped-frame count
  • Treating synthetic source frames as verified capture coordinates

Also prevent silent fallback, unpinned artifacts, missing cancellation, and conclusions that combine unlike configurations. Store unsuccessful runs alongside successful ones.

Minimum reproducibility record

LayerRecord
DeviceManufacturer, model, chipset, RAM class, operating-system build
SoftwareApplication version and git commit
ModelFamily, variant, revision, format, file length, hash, quantization
RuntimeName, revision, requested backend, observed backend evidence
WorkloadFixture revision, input hash, prompt hash, output policy
OutcomeCompleted, failed, cancelled, fallback, and privacy-safe diagnostics

Release checklist

  • ☐ The primary query is answered without an unsupported number.
  • ☐ Every artifact and runtime is pinned.
  • ☐ The representative task and failure policy are explicit.
  • ☐ Lifecycle, cancellation, cleanup, and fallback are tested.
  • ☐ User-content and network boundaries are documented.
  • ☐ Result wording applies only to the recorded configuration.
  • ☐ The page links to raw method or evidence when results are added.

Sources and related evidence

Chinese deployment and troubleshooting content is organized in the .奇连 AI 端侧专题.

Frequently asked questions

Does AudioRecord.getTimestamp give the end time of my latest read buffer?

No. Android says the timestamp reflects frame delivery at the earliest point available in the capture pipeline; AudioTimestamp.nanoTime estimates capture time for framePosition. Establish the read-buffer offset separately.

Can I set the first successful read to frame zero?

Not without evidence. A pure PCM fixture with synthetic P/T values checks arithmetic only; its source-frame label is not a real capture position. If playing and recording a synthetic pulse, record the captured marker, route, method, and uncertainty. Do not calibrate to the nearest timestamp poll by default; if origin is unverified, leave mapping unknown.

Does a mismatch between timestamp and read counts prove frames were dropped?

No. It can reflect buffering, delayed reads, recorder resets, route changes, transformation, or data loss. Compare repeated successful anchors with read results and independent event records before classifying a gap.

Can I compare AudioTimestamp nanoTime to wall-clock dates?

Not directly. The call selects MONOTONIC or BOOTTIME, which correspond to documented monotonic Android clock domains. Store the base and compare only values with a compatible origin and lifetime; keep calendar time as a separate field.