refactor: rename Audio Room → Nest project-wide
Aligns class names, package paths, string resource keys, UI text and intent actions with the Nests branding used by the EGG specs in nestsClient/specs/. Mechanical rename — no behavior change. - Folders: audiorooms/ → nests/ (5 paths across amethyst, quartz) - 30+ class renames (AudioRoom* → Nest*, AudioRooms* → Nests*) - String resource keys audio_room_* → nest_* - UI strings "Audio Room"/"Audio Rooms" → "Nest"/"Nests" (incl. all locales) - Intent extras AUDIO_ROOM_* → NEST_* - Compose route Route.AudioRooms → Route.Nests Spec-aligned identifiers (MeetingSpaceEvent, meetingSpaces/, the nip53* packages) are intentionally untouched — those are NIP-53 protocol names, not "audio room" branding. https://claude.ai/code/session_01RDpuki4t8StSg1CZcXnV5b
This commit is contained in:
+1
-1
@@ -38,7 +38,7 @@ import java.util.concurrent.atomic.AtomicLong
|
||||
* Moq-lite-backed [NestsListener]. Wraps a connected [MoqLiteSession]
|
||||
* and exposes the same listener API the IETF [DefaultNestsListener]
|
||||
* does, so [connectNestsListener] can swap the framing layer without
|
||||
* changing the public surface that [com.vitorpamplona.amethyst.commons.viewmodels.AudioRoomViewModel]
|
||||
* changing the public surface that [com.vitorpamplona.amethyst.commons.viewmodels.NestViewModel]
|
||||
* and downstream UI consume.
|
||||
*
|
||||
* Subscription mapping per the audio-rooms NIP draft + nests JS
|
||||
|
||||
+3
-3
@@ -21,7 +21,7 @@
|
||||
package com.vitorpamplona.nestsclient
|
||||
|
||||
import com.vitorpamplona.nestsclient.audio.AudioCapture
|
||||
import com.vitorpamplona.nestsclient.audio.AudioRoomMoqLiteBroadcaster
|
||||
import com.vitorpamplona.nestsclient.audio.NestMoqLiteBroadcaster
|
||||
import com.vitorpamplona.nestsclient.audio.OpusEncoder
|
||||
import com.vitorpamplona.nestsclient.moq.lite.MoqLitePublisherHandle
|
||||
import com.vitorpamplona.nestsclient.moq.lite.MoqLiteSession
|
||||
@@ -76,7 +76,7 @@ class MoqLiteNestsSpeaker internal constructor(
|
||||
throw t
|
||||
}
|
||||
val broadcaster =
|
||||
AudioRoomMoqLiteBroadcaster(
|
||||
NestMoqLiteBroadcaster(
|
||||
capture = captureFactory(),
|
||||
encoder = encoderFactory(),
|
||||
publisher = publisher,
|
||||
@@ -139,7 +139,7 @@ class MoqLiteNestsSpeaker internal constructor(
|
||||
}
|
||||
|
||||
internal class MoqLiteBroadcastHandle(
|
||||
private val broadcaster: AudioRoomMoqLiteBroadcaster,
|
||||
private val broadcaster: NestMoqLiteBroadcaster,
|
||||
private val publisher: MoqLitePublisherHandle,
|
||||
private val parent: MoqLiteNestsSpeaker,
|
||||
) : BroadcastHandle {
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
package com.vitorpamplona.nestsclient
|
||||
|
||||
import com.vitorpamplona.nestsclient.audio.AudioCapture
|
||||
import com.vitorpamplona.nestsclient.audio.AudioRoomBroadcaster
|
||||
import com.vitorpamplona.nestsclient.audio.NestBroadcaster
|
||||
import com.vitorpamplona.nestsclient.audio.OpusEncoder
|
||||
import com.vitorpamplona.nestsclient.moq.MoqProtocolException
|
||||
import com.vitorpamplona.nestsclient.moq.MoqSession
|
||||
@@ -133,7 +133,7 @@ sealed class NestsSpeakerState {
|
||||
* unit-test suite (`NestsSpeakerTest`) and for any future IETF
|
||||
* MoQ-transport target.
|
||||
*
|
||||
* Wraps a connected [MoqSession] and plumbs an [AudioRoomBroadcaster]
|
||||
* Wraps a connected [MoqSession] and plumbs an [NestBroadcaster]
|
||||
* through it on [startBroadcasting]. Construction does NOT open the
|
||||
* transport.
|
||||
*/
|
||||
@@ -168,7 +168,7 @@ class DefaultNestsSpeaker internal constructor(
|
||||
throw t
|
||||
}
|
||||
val broadcaster =
|
||||
AudioRoomBroadcaster(
|
||||
NestBroadcaster(
|
||||
capture = captureFactory(),
|
||||
encoder = encoderFactory(),
|
||||
publisher = publisher,
|
||||
@@ -236,7 +236,7 @@ class DefaultNestsSpeaker internal constructor(
|
||||
}
|
||||
|
||||
internal class DefaultBroadcastHandle(
|
||||
private val broadcaster: AudioRoomBroadcaster,
|
||||
private val broadcaster: NestBroadcaster,
|
||||
private val announce: MoqSession.AnnounceHandle,
|
||||
private val parent: DefaultNestsSpeaker,
|
||||
) : BroadcastHandle {
|
||||
|
||||
+4
-4
@@ -28,7 +28,7 @@ import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Inverse of [AudioRoomPlayer]: pulls PCM from an [AudioCapture], runs it
|
||||
* Inverse of [NestPlayer]: pulls PCM from an [AudioCapture], runs it
|
||||
* through an [OpusEncoder], and pushes the resulting Opus packets into a
|
||||
* [MoqSession.TrackPublisher] as MoQ OBJECT_DATAGRAMs.
|
||||
*
|
||||
@@ -46,7 +46,7 @@ import kotlinx.coroutines.launch
|
||||
* Encode failures are reported via [onError] but do NOT tear the loop down —
|
||||
* one bad frame shouldn't end the broadcast.
|
||||
*/
|
||||
class AudioRoomBroadcaster(
|
||||
class NestBroadcaster(
|
||||
private val capture: AudioCapture,
|
||||
private val encoder: OpusEncoder,
|
||||
private val publisher: MoqSession.TrackPublisher,
|
||||
@@ -66,8 +66,8 @@ class AudioRoomBroadcaster(
|
||||
* surface it to the user.
|
||||
*/
|
||||
fun start(onError: (AudioException) -> Unit = { /* swallow */ }) {
|
||||
check(!stopped) { "AudioRoomBroadcaster already stopped" }
|
||||
check(job == null) { "AudioRoomBroadcaster.start already called" }
|
||||
check(!stopped) { "NestBroadcaster already stopped" }
|
||||
check(job == null) { "NestBroadcaster.start already called" }
|
||||
|
||||
// Audit round-2 MoQ #7: capture.start() can throw before we have
|
||||
// a job. Mark stopped + propagate so a half-started capture isn't
|
||||
+4
-4
@@ -28,7 +28,7 @@ import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Mirror of [AudioRoomBroadcaster] but driving a moq-lite
|
||||
* Mirror of [NestBroadcaster] but driving a moq-lite
|
||||
* [MoqLitePublisherHandle] instead of an IETF `MoqSession.TrackPublisher`.
|
||||
* Keeps the IETF broadcaster intact for the IETF unit-test suite while
|
||||
* letting the production speaker path use moq-lite.
|
||||
@@ -36,7 +36,7 @@ import kotlinx.coroutines.launch
|
||||
* Lifecycle and audit comments mirror the IETF version 1:1 — only the
|
||||
* sink type changes.
|
||||
*/
|
||||
class AudioRoomMoqLiteBroadcaster(
|
||||
class NestMoqLiteBroadcaster(
|
||||
private val capture: AudioCapture,
|
||||
private val encoder: OpusEncoder,
|
||||
private val publisher: MoqLitePublisherHandle,
|
||||
@@ -55,8 +55,8 @@ class AudioRoomMoqLiteBroadcaster(
|
||||
* the exception propagates.
|
||||
*/
|
||||
fun start(onError: (AudioException) -> Unit = { /* swallow */ }) {
|
||||
check(!stopped) { "AudioRoomMoqLiteBroadcaster already stopped" }
|
||||
check(job == null) { "AudioRoomMoqLiteBroadcaster.start already called" }
|
||||
check(!stopped) { "NestMoqLiteBroadcaster already stopped" }
|
||||
check(job == null) { "NestMoqLiteBroadcaster.start already called" }
|
||||
|
||||
try {
|
||||
capture.start()
|
||||
+4
-4
@@ -33,7 +33,7 @@ import kotlinx.coroutines.launch
|
||||
* through an [OpusDecoder] into an [AudioPlayer].
|
||||
*
|
||||
* Single-track. To play multiple speakers in a room, instantiate one
|
||||
* [AudioRoomPlayer] per [com.vitorpamplona.nestsclient.moq.SubscribeHandle];
|
||||
* [NestPlayer] per [com.vitorpamplona.nestsclient.moq.SubscribeHandle];
|
||||
* each owns its own decoder (Opus state is per-track).
|
||||
*
|
||||
* Lifecycle:
|
||||
@@ -41,7 +41,7 @@ import kotlinx.coroutines.launch
|
||||
* - [stop] cancels the decode loop, stops the player, and releases the
|
||||
* decoder. Idempotent.
|
||||
*/
|
||||
class AudioRoomPlayer(
|
||||
class NestPlayer(
|
||||
private val decoder: OpusDecoder,
|
||||
private val player: AudioPlayer,
|
||||
private val scope: CoroutineScope,
|
||||
@@ -61,8 +61,8 @@ class AudioRoomPlayer(
|
||||
objects: Flow<MoqObject>,
|
||||
onError: (AudioException) -> Unit = { /* swallow */ },
|
||||
) {
|
||||
check(!stopped) { "AudioRoomPlayer already stopped" }
|
||||
check(job == null) { "AudioRoomPlayer.play already called" }
|
||||
check(!stopped) { "NestPlayer already stopped" }
|
||||
check(job == null) { "NestPlayer.play already called" }
|
||||
|
||||
player.start()
|
||||
job =
|
||||
+6
-6
@@ -28,14 +28,14 @@ import kotlin.test.assertContentEquals
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class AudioRoomBroadcasterTest {
|
||||
class NestBroadcasterTest {
|
||||
@Test
|
||||
fun pcm_frames_flow_through_encoder_into_publisher_in_order() =
|
||||
runTest {
|
||||
val capture = ScriptedCapture(listOf(shortArrayOf(1), shortArrayOf(2), shortArrayOf(3)))
|
||||
val encoder = ScriptedEncoder(prefix = byteArrayOf(0xAA.toByte()))
|
||||
val publisher = RecordingPublisher("track")
|
||||
val broadcaster = AudioRoomBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
val broadcaster = NestBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
|
||||
broadcaster.start()
|
||||
// Capture exhausts after 3 frames (readFrame returns null) so the
|
||||
@@ -61,7 +61,7 @@ class AudioRoomBroadcasterTest {
|
||||
val capture = ScriptedCapture(listOf(shortArrayOf(1), shortArrayOf(2), shortArrayOf(3)))
|
||||
val encoder = ScriptedEncoder(prefix = byteArrayOf(0xBB.toByte()))
|
||||
val publisher = RecordingPublisher("track")
|
||||
val broadcaster = AudioRoomBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
val broadcaster = NestBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
|
||||
broadcaster.setMuted(true)
|
||||
broadcaster.start()
|
||||
@@ -81,7 +81,7 @@ class AudioRoomBroadcasterTest {
|
||||
val capture = ScriptedCapture(listOf(shortArrayOf(1), shortArrayOf(2)))
|
||||
val encoder = ScriptedEncoder(prefix = byteArrayOf(0xCC.toByte()), warmupSkips = 1)
|
||||
val publisher = RecordingPublisher("track")
|
||||
val broadcaster = AudioRoomBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
val broadcaster = NestBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
|
||||
broadcaster.start()
|
||||
capture.awaitDrained()
|
||||
@@ -100,7 +100,7 @@ class AudioRoomBroadcasterTest {
|
||||
val capture = ScriptedCapture(listOf(shortArrayOf(1), shortArrayOf(2), shortArrayOf(3)))
|
||||
val encoder = ScriptedEncoder(prefix = byteArrayOf(0xDD.toByte()), failOnNthCall = 1)
|
||||
val publisher = RecordingPublisher("track")
|
||||
val broadcaster = AudioRoomBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
val broadcaster = NestBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
val errors = mutableListOf<AudioException>()
|
||||
|
||||
broadcaster.start { errors.add(it) }
|
||||
@@ -117,7 +117,7 @@ class AudioRoomBroadcasterTest {
|
||||
val capture = ScriptedCapture(listOf(shortArrayOf(1)))
|
||||
val encoder = ScriptedEncoder(prefix = byteArrayOf(0xEE.toByte()))
|
||||
val publisher = RecordingPublisher("track")
|
||||
val broadcaster = AudioRoomBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
val broadcaster = NestBroadcaster(capture, encoder, publisher, backgroundScope)
|
||||
|
||||
broadcaster.start()
|
||||
capture.awaitDrained()
|
||||
+8
-8
@@ -31,7 +31,7 @@ import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class AudioRoomPlayerTest {
|
||||
class NestPlayerTest {
|
||||
@Test
|
||||
fun every_object_payload_is_decoded_and_enqueued_in_order() =
|
||||
runTest {
|
||||
@@ -45,7 +45,7 @@ class AudioRoomPlayerTest {
|
||||
moqObject(byteArrayOf(0x04, 0x05, 0x06)),
|
||||
)
|
||||
|
||||
val sut = AudioRoomPlayer(decoder, player, this)
|
||||
val sut = NestPlayer(decoder, player, this)
|
||||
sut.play(objects)
|
||||
testScheduler.advanceUntilIdle()
|
||||
|
||||
@@ -83,7 +83,7 @@ class AudioRoomPlayerTest {
|
||||
moqObject(byteArrayOf(0x02)),
|
||||
)
|
||||
|
||||
val sut = AudioRoomPlayer(decoder, player, this)
|
||||
val sut = NestPlayer(decoder, player, this)
|
||||
sut.play(objects, onError = { errors.add(it) })
|
||||
testScheduler.advanceUntilIdle()
|
||||
|
||||
@@ -102,7 +102,7 @@ class AudioRoomPlayerTest {
|
||||
runTest {
|
||||
val decoder = FakeOpusDecoder { byteToShorts(it) }
|
||||
val player = FakeAudioPlayer()
|
||||
val sut = AudioRoomPlayer(decoder, player, this)
|
||||
val sut = NestPlayer(decoder, player, this)
|
||||
sut.play(flowOf())
|
||||
testScheduler.advanceUntilIdle()
|
||||
sut.stop()
|
||||
@@ -115,7 +115,7 @@ class AudioRoomPlayerTest {
|
||||
fun play_cannot_be_called_twice_on_the_same_instance() =
|
||||
runTest {
|
||||
val sut =
|
||||
AudioRoomPlayer(
|
||||
NestPlayer(
|
||||
FakeOpusDecoder { byteToShorts(it) },
|
||||
FakeAudioPlayer(),
|
||||
this,
|
||||
@@ -129,7 +129,7 @@ class AudioRoomPlayerTest {
|
||||
fun play_after_stop_is_rejected() =
|
||||
runTest {
|
||||
val sut =
|
||||
AudioRoomPlayer(
|
||||
NestPlayer(
|
||||
FakeOpusDecoder { byteToShorts(it) },
|
||||
FakeAudioPlayer(),
|
||||
this,
|
||||
@@ -143,7 +143,7 @@ class AudioRoomPlayerTest {
|
||||
runTest {
|
||||
val decoder = FakeOpusDecoder { ShortArray(0) }
|
||||
val player = FakeAudioPlayer()
|
||||
val sut = AudioRoomPlayer(decoder, player, this)
|
||||
val sut = NestPlayer(decoder, player, this)
|
||||
sut.play(flowOf(moqObject(byteArrayOf(0x01))))
|
||||
testScheduler.advanceUntilIdle()
|
||||
assertEquals(0, player.queued.size)
|
||||
@@ -157,7 +157,7 @@ class AudioRoomPlayerTest {
|
||||
val decoder = FakeOpusDecoder { byteToShorts(it) }
|
||||
val player = FakeAudioPlayer()
|
||||
|
||||
val sut = AudioRoomPlayer(decoder, player, this)
|
||||
val sut = NestPlayer(decoder, player, this)
|
||||
sut.play(channel.receiveAsFlow())
|
||||
testScheduler.runCurrent()
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ import kotlin.test.fail
|
||||
* - the broadcaster keeps the capture pump running while muted (so
|
||||
* unmute is sample-accurate)
|
||||
* - frames pushed during mute do NOT reach subscribers (`if (muted)
|
||||
* continue` in [com.vitorpamplona.nestsclient.audio.AudioRoomMoqLiteBroadcaster])
|
||||
* continue` in [com.vitorpamplona.nestsclient.audio.NestMoqLiteBroadcaster])
|
||||
* - frames pushed before / after the muted window DO reach
|
||||
* subscribers, with the muted ones missing entirely (no silent
|
||||
* placeholder frames)
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ package com.vitorpamplona.nestsclient.interop
|
||||
import com.vitorpamplona.nestsclient.NestsRoomConfig
|
||||
import com.vitorpamplona.nestsclient.OkHttpNestsClient
|
||||
import com.vitorpamplona.nestsclient.audio.AudioCapture
|
||||
import com.vitorpamplona.nestsclient.audio.AudioRoomMoqLiteBroadcaster
|
||||
import com.vitorpamplona.nestsclient.audio.NestMoqLiteBroadcaster
|
||||
import com.vitorpamplona.nestsclient.audio.OpusEncoder
|
||||
import com.vitorpamplona.nestsclient.connectNestsListener
|
||||
import com.vitorpamplona.nestsclient.connectNestsSpeaker
|
||||
@@ -57,7 +57,7 @@ import kotlin.test.fail
|
||||
* (`MoqLitePublisherHandle`), the listener subscribes by speaker
|
||||
* pubkey (`broadcast=pubkey`, `track="audio/data"`), the speaker
|
||||
* pushes deterministic Opus-shaped payloads through the
|
||||
* [AudioRoomMoqLiteBroadcaster] pipeline, and the listener collects
|
||||
* [NestMoqLiteBroadcaster] pipeline, and the listener collects
|
||||
* them via [SubscribeHandle.objects] (which the moq-lite adapter
|
||||
* wraps over `MoqLiteFrame` so existing decoder / player code keeps
|
||||
* working).
|
||||
|
||||
Reference in New Issue
Block a user