Repository navigation
Tags
Tags
internal/oboe: update Oboe to 1.11.0 Regenerate the bundled sources and remove the local NDK 30 patches. Oboe now includes the NDK 30 compatibility fixes upstream. Co-Authored-By: Codex <noreply@openai.com>
oto: fix unsigned 8-bit sample conversion Widen samples to int before subtracting the midpoint so negative amplitudes do not wrap around in unsigned arithmetic. Add a regression test covering every unsigned 8-bit sample value. Closes #298 Co-Authored-By: Codex <noreply@openai.com>
oto: document that a player must stay reachable while playing A cleanup attached to the returned *Player closes the player, and the mux keeps only the inner implementation reachable, so the caller's handle is the wrapper's only GC root. Dropping the handle of a playing player lets the next collection close it in the middle of playback, and no error is recorded for it. Document the requirement on Context.NewPlayer and on the Player type. Closes #293 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
oto: keep non-finite values out of the mixed samples Mux.ReadFloat32s zeroes one shared buffer and lets every playing player accumulate into it, and the result reaches the drivers as is. A NaN or an infinite value from a single player therefore destroys the other players' samples, and converting such a value to an integer sample is undefined at the C level. A float32 source can supply NaN or infinity directly, and a volume larger than the maximum float32, infinity included, becomes +Inf when the mixing narrows the volume to float32; multiplying a 0 sample by +Inf results in NaN. Store the mixed value only when it is finite. The shared buffer then holds finite values only, and a broken player is dropped instead of the others. An accumulation that overflows the float32 range is covered as well. Treat a volume out of the range of [0, math.MaxFloat32], NaN included, as 0 in SetVolume. A negative volume is a phase inversion rather than a volume, and the mixing cannot reject it as it is a finite value. Document the actual contract of Volume and SetVolume. The mixing converts every format to float32 before multiplying by the volume, so a volume larger than 1 amplifies the sound instead of being clamped, with clipping left to the device. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
oto: add PauseAndStopReading and redeprecate Reset Reset clears the player's buffer, so a player resumed after Reset skips every byte that was already read from the source but not yet played. Making Reset the documented way to release the source turned a lossy operation into the recommended one. Add PauseAndStopReading, which stops reading the source without discarding the buffered data, so playing can be resumed by Play without a gap. Deprecate Reset again in favor of Pause, PauseAndStopReading, or Seek. Reset keeps waiting for an ongoing read, and is now that wait plus clearing the buffer. The result of an ongoing read is kept instead of being discarded whenever the player is in the stop-reading state. Only Seek invalidates it, as the data is at the old position, and a generation counter of the source position distinguishes the two cases. Closes #290 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
internal/oboe: fix a compile error with NDK 30 Oboe 1.10.0 guards the AAudio types it defines for itself with __NDK_MAJOR__ <= 30, but NDK 30 declares all of them, so AAudio_FallbackMode, AAudio_StretchMode and AAudioPlaybackParameters are redefined. AAudioStream_partialDataCallback is declared there as well and is redefined too, without an error: it is a typedef, and redeclaring one with the same type is allowed. Guard the whole block with < 30. AAudio_DeviceType is now an enum with an explicit underlying type rather than a typedef of int32_t, so ASSERT_INT32 no longer holds. Drop it. The static_asserts next to it cast to int32_t explicitly, and the remaining uses of the type are static_casts, which an enum satisfies. The oboe_* files are generator output, so make the changes in gen.go while copying instead. A replacement that no longer matches is an error, so bumping oboeVersion to a release that carries the upstream fix reports the stale replacement rather than quietly doing nothing. Verified with NDK 30.0.15729638-beta2 and 28.2.13676358, for android/arm64 and android/arm. Closes #287 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
internal/oboe: fix a compile error with NDK 30 Oboe 1.10.0 guards the AAudio types it defines for itself with __NDK_MAJOR__ <= 30, but NDK 30 declares all of them, so AAudio_FallbackMode, AAudio_StretchMode and AAudioPlaybackParameters are redefined. AAudioStream_partialDataCallback is declared there as well and is redefined too, without an error: it is a typedef, and redeclaring one with the same type is allowed. Guard the whole block with < 30. AAudio_DeviceType is now an enum with an explicit underlying type rather than a typedef of int32_t, so ASSERT_INT32 no longer holds. Drop it. The static_asserts next to it cast to int32_t explicitly, and the remaining uses of the type are static_casts, which an enum satisfies. The oboe_* files are generator output, so make the changes in gen.go while copying instead. A replacement that no longer matches is an error, so bumping oboeVersion to a release that carries the upstream fix reports the stale replacement rather than quietly doing nothing. Verified with NDK 30.0.15729638-beta2 and 28.2.13676358, for android/arm64 and android/arm. Closes #287 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
internal/oboe: fall back to OpenSL ES when AAudio fails An Android user reported 'oboe: Play failed: ErrorIllegalArgument', which Ebitengine surfaces as a fatal game error. ErrorIllegalArgument is AAUDIO_ERROR_ILLEGAL_ARGUMENT, a result no OpenSL ES path in Oboe returns, so it became reachable only when AAudio was enabled: the same device played through OpenSL ES before that. The configuration is unremarkable, an output stream that is low latency, shared, float, two channels, the requested sample rate and a data callback, with no buffer capacity requested. google/oboe#1293 reports the same result from openStream for an equally plain configuration on 11 device models, which the vendor could not reproduce and which was closed without a fix. A device that refuses what every other device plays is a platform bug that no argument here avoids, and treating it as a configuration error left the process with no audio at all. Fall back to OpenSL ES when starting fails for a reason that would not pass, and keep it for the rest of the process. It is the API this backend used on every device until AAudio, so it is what is left worth attempting before playing is given up on. The result does not say whether opening or starting failed, so the fallback covers both, and it covers the sharing mode check, which ended playing the same way. Below Android R the API is already OpenSL ES, so nothing changes there. Only a failure of both APIs is reported now. Updates #284 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PreviousNext