Commit Graph

5 Commits

Author SHA1 Message Date
62ced89701 Pick the Android audio devices, microphone preset and playback usage
Microphone and speaker are chosen separately, so a Bluetooth headset can
play in media quality while the phone's own microphone listens, instead of
the headset dropping into its call profile. Devices are kept by type and
address: Android hands out new ids whenever one reconnects, and a line that
lost its device comes back to it when it returns.

The microphone preset (voice recognition by default, or the platform's
call processing, unprocessed, ...) and whether voices play as media or as
a call are Android's own settings. Changing either reopens the open
streams in place. Communication mode, and the headset's call link that a
Bluetooth microphone needs, are held only while a stream needs them, and
are set up before that stream opens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 18:31:22 +00:00
967fcadf77 Keep chat drafts per conversation and open each at its newest line
Switching conversations dropped the message being written, and showed
the next one at the scroll position of the last.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 15:12:50 +00:00
941365cab0 Give the Android app its real UI
- Connect screen with an address or a bookmark, which can be added and
  removed there.
- Server screen: the channel tree with each client's status, folding
  channels, joining (asking for a password where needed) and
  subscribing from a channel's sheet; private message, poke and volume
  from a client's sheet.
- Chat: the server log, the channel and private conversations with
  their history, unread marks, BBCode and clickable client, channel and
  web links. Chat lines are the HTML the desktop shows, turned into
  styled text.
- Voice bar: mute, deafen, away, and a hold-to-talk button in
  push-to-talk mode. The microphone permission is asked for on connect.
- Settings: nickname, transmission mode, voice activation, noise
  suppression, gain control and playback volume, in effect at once.

The session's state reaches Compose as immutable snapshots: the tree
at most every 30 ms, rebuilt only when channels or clients changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 14:21:51 +00:00
b3ad3ceda0 Keep the Android connection alive in the background
The session moves from the connection screen's ViewModel into an
app-wide SessionController, and a foreground service keeps the process
running while connected:

- Its notification shows the server and status and offers Mute, Deafen
  and Disconnect.
- It declares microphone use only once the microphone is handed to the
  connection, as Android requires that permission to be granted then.
- It holds a low-latency Wi-Fi lock and a CPU wake lock, since voice
  goes out every 20 ms.
- When the system moves to another network, the session reconnects to
  where it was, as its socket stays bound to the old one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 08:28:36 +00:00
086b913c8e Add the Android app: Gradle build, Oboe audio, connection screen
android/ builds core and ts3j from the same sources as the desktop's
Maven build, so the app shares all of the client's logic:

- audio: Oboe streams behind AudioCapture/AudioPlayback, with a lock-free
  ring between the real-time callback and the blocking Java side, and
  libopus 1.5.2 built with the NDK behind OpusCodec. Speakers are mixed
  onto one stream. Capture uses the VoiceRecognition preset, leaving
  noise suppression and gain to the client's own processing.
- app: a plain connection screen to try the port out - connect,
  microphone, mute, deafen, channel chat and a log - until the real UI.

Targets Android 13 and up (minSdk 33) on arm64 and x86_64.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 08:24:21 +00:00