mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-13 23:37:22 +00:00
[client/idd] network: discard stale audio after stalls
Keep PCM and its clock sample in cancellable datagrams so recovery cannot replay audio buffered before a Wi-Fi stall. Drop blocked real-time packets with an explicit discontinuity and make a newer reconnect supersede stale audio authorities.
This commit is contained in:
@@ -116,10 +116,11 @@ typedef struct LG_AudioEventOps
|
|||||||
uint8_t channels, const uint16_t volume[]);
|
uint8_t channels, const uint16_t volume[]);
|
||||||
void (*playbackMute)(void * opaque, uint32_t generation, bool mute);
|
void (*playbackMute)(void * opaque, uint32_t generation, bool mute);
|
||||||
/* Sample data is borrowed for the duration of the call. When supplied, the
|
/* Sample data is borrowed for the duration of the call. When supplied, the
|
||||||
* source clock position and time identify the first frame in this packet. */
|
* source clock position and time identify the first frame in this packet.
|
||||||
|
* Discontinuity remains valid when no source clock is available. */
|
||||||
void (*playbackData)(void * opaque, uint32_t generation,
|
void (*playbackData)(void * opaque, uint32_t generation,
|
||||||
const void * data, size_t frames,
|
const void * data, size_t frames,
|
||||||
const LG_AudioClock * sourceClock);
|
const LG_AudioClock * sourceClock, bool discontinuity);
|
||||||
|
|
||||||
/* May repeat with the same generation to update an active stream format. */
|
/* May repeat with the same generation to update an active stream format. */
|
||||||
void (*recordStart)(void * opaque, uint32_t generation,
|
void (*recordStart)(void * opaque, uint32_t generation,
|
||||||
|
|||||||
@@ -2294,7 +2294,8 @@ static void playbackResetRateControl(PlaybackSourceData * sourceData,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static PlaybackDataResult playbackData(const void * data, size_t frameCount,
|
static PlaybackDataResult playbackData(const void * data, size_t frameCount,
|
||||||
const LG_AudioClock * sourceClock, int64_t arrivalTime)
|
const LG_AudioClock * sourceClock, bool streamDiscontinuity,
|
||||||
|
int64_t arrivalTime)
|
||||||
{
|
{
|
||||||
StreamState state = playbackGetState();
|
StreamState state = playbackGetState();
|
||||||
if (state == STREAM_STATE_STOP_PENDING)
|
if (state == STREAM_STATE_STOP_PENDING)
|
||||||
@@ -2363,8 +2364,9 @@ static PlaybackDataResult playbackData(const void * data, size_t frameCount,
|
|||||||
const bool bufferUnderrun =
|
const bool bufferUnderrun =
|
||||||
STREAM_ACTIVE(playbackGetState()) &&
|
STREAM_ACTIVE(playbackGetState()) &&
|
||||||
ringbuffer_getCount(audio.playback.buffer) < 0;
|
ringbuffer_getCount(audio.playback.buffer) < 0;
|
||||||
bool discontinuity =
|
bool discontinuity = bufferUnderrun ||
|
||||||
bufferUnderrun || (sourceClock && sourceClock->discontinuity);
|
streamDiscontinuity ||
|
||||||
|
(sourceClock && sourceClock->discontinuity);
|
||||||
const int64_t previousArrivalTime = sourceData->lastArrivalTime;
|
const int64_t previousArrivalTime = sourceData->lastArrivalTime;
|
||||||
const int64_t packetTime =
|
const int64_t packetTime =
|
||||||
playbackMapMediaTime(sourceData, sourceClock, frames,
|
playbackMapMediaTime(sourceData, sourceClock, frames,
|
||||||
@@ -4039,11 +4041,12 @@ static void eventPlaybackMute(void * opaque, uint32_t generation, bool mute)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void eventPlaybackData(void * opaque, uint32_t generation,
|
static void eventPlaybackData(void * opaque, uint32_t generation,
|
||||||
const void * data, size_t frames, const LG_AudioClock * sourceClock)
|
const void * data, size_t frames, const LG_AudioClock * sourceClock,
|
||||||
|
bool discontinuity)
|
||||||
{
|
{
|
||||||
const int64_t arrivalTime = nanotime();
|
const int64_t arrivalTime = nanotime();
|
||||||
AudioBinding * binding = opaque;
|
AudioBinding * binding = opaque;
|
||||||
AudioBinding active;
|
AudioBinding active;
|
||||||
|
|
||||||
if (!eventBegin(binding, &active))
|
if (!eventBegin(binding, &active))
|
||||||
return;
|
return;
|
||||||
@@ -4057,7 +4060,8 @@ static void eventPlaybackData(void * opaque, uint32_t generation,
|
|||||||
PlaybackDataResult result = PLAYBACK_DATA_DROP;
|
PlaybackDataResult result = PLAYBACK_DATA_DROP;
|
||||||
if (liveGeneration == generation)
|
if (liveGeneration == generation)
|
||||||
{
|
{
|
||||||
result = playbackData(data, frames, sourceClock, arrivalTime);
|
result = playbackData(
|
||||||
|
data, frames, sourceClock, discontinuity, arrivalTime);
|
||||||
|
|
||||||
if (result == PLAYBACK_DATA_PROCESSED &&
|
if (result == PLAYBACK_DATA_PROCESSED &&
|
||||||
atomic_load_explicit(&audio.playback.streamGeneration,
|
atomic_load_explicit(&audio.playback.streamGeneration,
|
||||||
|
|||||||
@@ -593,7 +593,7 @@ static void testPlaybackRetry(void)
|
|||||||
atomic_store(&b.setupOK, true);
|
atomic_store(&b.setupOK, true);
|
||||||
uint8_t frames[480 * 2 * 2] = { 0 };
|
uint8_t frames[480 * 2 * 2] = { 0 };
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
p.events->playbackData(p.eventOpaque, 11, frames, 480, NULL);
|
p.events->playbackData(p.eventOpaque, 11, frames, 480, NULL, false);
|
||||||
waitFor(&b.setupN, failed + 1);
|
waitFor(&b.setupN, failed + 1);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < WAIT_MS; ++i)
|
for (unsigned int i = 0; i < WAIT_MS; ++i)
|
||||||
@@ -605,7 +605,7 @@ static void testPlaybackRetry(void)
|
|||||||
}
|
}
|
||||||
CHECK(atomic_load(&audio.playback.streamGeneration) == 11);
|
CHECK(atomic_load(&audio.playback.streamGeneration) == 11);
|
||||||
for (unsigned int i = 0; i < 8; ++i)
|
for (unsigned int i = 0; i < 8; ++i)
|
||||||
p.events->playbackData(p.eventOpaque, 11, frames, 480, NULL);
|
p.events->playbackData(p.eventOpaque, 11, frames, 480, NULL, false);
|
||||||
waitFor(&b.playStartN, 1);
|
waitFor(&b.playStartN, 1);
|
||||||
|
|
||||||
LG_AudioFailureFn fail = b.playFail;
|
LG_AudioFailureFn fail = b.playFail;
|
||||||
@@ -617,7 +617,7 @@ static void testPlaybackRetry(void)
|
|||||||
|
|
||||||
const unsigned int retry = atomic_load(&b.setupN);
|
const unsigned int retry = atomic_load(&b.setupN);
|
||||||
usleep(10000);
|
usleep(10000);
|
||||||
p.events->playbackData(p.eventOpaque, 11, frames, 480, NULL);
|
p.events->playbackData(p.eventOpaque, 11, frames, 480, NULL, false);
|
||||||
waitFor(&b.setupN, retry + 1);
|
waitFor(&b.setupN, retry + 1);
|
||||||
|
|
||||||
p.events->playbackStop(p.eventOpaque, 11);
|
p.events->playbackStop(p.eventOpaque, 11);
|
||||||
@@ -679,7 +679,7 @@ static void testPlaybackRecovery(void)
|
|||||||
CHECK(ringbuffer_consume(audio.playback.buffer, NULL, 16) == 16);
|
CHECK(ringbuffer_consume(audio.playback.buffer, NULL, 16) == 16);
|
||||||
CHECK(ringbuffer_getCount(audio.playback.buffer) == -16);
|
CHECK(ringbuffer_getCount(audio.playback.buffer) == -16);
|
||||||
uint8_t frames[1200 * 2 * 2] = { 0 };
|
uint8_t frames[1200 * 2 * 2] = { 0 };
|
||||||
CHECK(playbackData(frames, 1200, NULL, arrival) ==
|
CHECK(playbackData(frames, 1200, NULL, false, arrival) ==
|
||||||
PLAYBACK_DATA_PROCESSED);
|
PLAYBACK_DATA_PROCESSED);
|
||||||
|
|
||||||
CHECK(source->sourcePacketDurationSec < 0.010);
|
CHECK(source->sourcePacketDurationSec < 0.010);
|
||||||
@@ -690,12 +690,12 @@ static void testPlaybackRecovery(void)
|
|||||||
CHECK(fabs(atomic_load(&audio.playback.backendResampleRatio) -
|
CHECK(fabs(atomic_load(&audio.playback.backendResampleRatio) -
|
||||||
source->lastClockRatio) < 0.000001);
|
source->lastClockRatio) < 0.000001);
|
||||||
|
|
||||||
CHECK(playbackData(frames, 1200, NULL, arrival + 1000) ==
|
CHECK(playbackData(frames, 1200, NULL, false, arrival + 1000) ==
|
||||||
PLAYBACK_DATA_PROCESSED);
|
PLAYBACK_DATA_PROCESSED);
|
||||||
CHECK(source->sourcePacketDurationSec < 0.010);
|
CHECK(source->sourcePacketDurationSec < 0.010);
|
||||||
CHECK(source->sourcePacketRecovering);
|
CHECK(source->sourcePacketRecovering);
|
||||||
|
|
||||||
CHECK(playbackData(frames, 480, NULL,
|
CHECK(playbackData(frames, 480, NULL, false,
|
||||||
arrival + INT64_C(10000000)) == PLAYBACK_DATA_PROCESSED);
|
arrival + INT64_C(10000000)) == PLAYBACK_DATA_PROCESSED);
|
||||||
CHECK(!source->sourcePacketRecovering);
|
CHECK(!source->sourcePacketRecovering);
|
||||||
CHECK(fabs(source->sourcePacketDurationSec - 0.010) < 0.000001);
|
CHECK(fabs(source->sourcePacketDurationSec - 0.010) < 0.000001);
|
||||||
@@ -733,7 +733,7 @@ static void testPlaybackStableUnderrun(void)
|
|||||||
uint8_t frames[64 * 2 * 2];
|
uint8_t frames[64 * 2 * 2];
|
||||||
uint8_t output[64 * 2 * 2];
|
uint8_t output[64 * 2 * 2];
|
||||||
memset(frames, 0x5a, sizeof(frames));
|
memset(frames, 0x5a, sizeof(frames));
|
||||||
CHECK(playbackData(frames, 64, NULL, arrival) ==
|
CHECK(playbackData(frames, 64, NULL, false, arrival) ==
|
||||||
PLAYBACK_DATA_PROCESSED);
|
PLAYBACK_DATA_PROCESSED);
|
||||||
|
|
||||||
const int recoveredOccupancy =
|
const int recoveredOccupancy =
|
||||||
@@ -765,7 +765,7 @@ static void testPlaybackStableUnderrun(void)
|
|||||||
source->devicePositionOffsetFrames;
|
source->devicePositionOffsetFrames;
|
||||||
const int64_t secondPacketArrival = arrival +
|
const int64_t secondPacketArrival = arrival +
|
||||||
llrint(64.0e9 / format.sampleRate);
|
llrint(64.0e9 / format.sampleRate);
|
||||||
CHECK(playbackData(frames, 64, NULL,
|
CHECK(playbackData(frames, 64, NULL, false,
|
||||||
secondPacketArrival) == PLAYBACK_DATA_PROCESSED);
|
secondPacketArrival) == PLAYBACK_DATA_PROCESSED);
|
||||||
CHECK(source->devicePositionOffsetFrames == recoveredOffset);
|
CHECK(source->devicePositionOffsetFrames == recoveredOffset);
|
||||||
CHECK(ringbuffer_getCount(audio.playback.buffer) ==
|
CHECK(ringbuffer_getCount(audio.playback.buffer) ==
|
||||||
@@ -852,7 +852,7 @@ static void testPlaybackResume(void)
|
|||||||
CHECK(atomic_load(&b.setupN) == setupN);
|
CHECK(atomic_load(&b.setupN) == setupN);
|
||||||
|
|
||||||
uint8_t input[480 * 2 * 2] = { 0 };
|
uint8_t input[480 * 2 * 2] = { 0 };
|
||||||
p.events->playbackData(p.eventOpaque, 12, input, 480, NULL);
|
p.events->playbackData(p.eventOpaque, 12, input, 480, NULL, false);
|
||||||
CHECK(atomic_load(&audio.playback.streamGeneration) == 12);
|
CHECK(atomic_load(&audio.playback.streamGeneration) == 12);
|
||||||
CHECK(playbackGetState() == STREAM_STATE_RUN);
|
CHECK(playbackGetState() == STREAM_STATE_RUN);
|
||||||
CHECK(atomic_load(&audio.playback.underruns) == 0);
|
CHECK(atomic_load(&audio.playback.underruns) == 0);
|
||||||
@@ -883,7 +883,7 @@ static void testPlaybackResume(void)
|
|||||||
|
|
||||||
p.events->playbackStart(p.eventOpaque, 13, &format, NULL);
|
p.events->playbackStart(p.eventOpaque, 13, &format, NULL);
|
||||||
CHECK(atomic_load(&audio.playback.streamGeneration) == 13);
|
CHECK(atomic_load(&audio.playback.streamGeneration) == 13);
|
||||||
p.events->playbackData(p.eventOpaque, 13, input, 480, NULL);
|
p.events->playbackData(p.eventOpaque, 13, input, 480, NULL, false);
|
||||||
CHECK(playbackGetState() == STREAM_STATE_RUN);
|
CHECK(playbackGetState() == STREAM_STATE_RUN);
|
||||||
CHECK(source->deviceClock.time == arrival);
|
CHECK(source->deviceClock.time == arrival);
|
||||||
CHECK(source->deviceClock.position == idleFrames);
|
CHECK(source->deviceClock.position == idleFrames);
|
||||||
|
|||||||
@@ -150,21 +150,23 @@ static unsigned audioSampleBytes(LG_AudioSampleFormat format)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void playbackData(void * opaque, uint32_t generation,
|
static void playbackData(void * opaque, uint32_t generation,
|
||||||
const void * data, size_t frames, const LG_AudioClock * clock)
|
const void * data, size_t frames, const LG_AudioClock * clock,
|
||||||
|
bool discontinuity)
|
||||||
{
|
{
|
||||||
struct Trace * trace = opaque;
|
struct Trace * trace = opaque;
|
||||||
|
(void)discontinuity;
|
||||||
pthread_mutex_lock(&trace->mutex);
|
pthread_mutex_lock(&trace->mutex);
|
||||||
trace->playGeneration = generation;
|
trace->playGeneration = generation;
|
||||||
trace->playFrames = frames;
|
trace->playFrames = frames;
|
||||||
const size_t bytes = frames * trace->playFormat.channelCount *
|
const size_t bytes = frames * trace->playFormat.channelCount *
|
||||||
audioSampleBytes(trace->playFormat.sampleFormat);
|
audioSampleBytes(trace->playFormat.sampleFormat);
|
||||||
const size_t copy = bytes < sizeof(trace->playData) ?
|
const size_t copy = bytes < sizeof(trace->playData) ?
|
||||||
bytes : sizeof(trace->playData);
|
bytes : sizeof(trace->playData);
|
||||||
memset(trace->playData, 0, sizeof(trace->playData));
|
memset(trace->playData, 0, sizeof(trace->playData));
|
||||||
memcpy(trace->playData, data, copy);
|
memcpy(trace->playData, data, copy);
|
||||||
trace->playClockValid = clock != NULL;
|
trace->playClockValid = clock != NULL;
|
||||||
if (clock)
|
if (clock)
|
||||||
trace->playClock = *clock;
|
trace->playClock = *clock;
|
||||||
pthread_mutex_unlock(&trace->mutex);
|
pthread_mutex_unlock(&trace->mutex);
|
||||||
traceEvent(trace, TRACE_PLAY_DATA, generation);
|
traceEvent(trace, TRACE_PLAY_DATA, generation);
|
||||||
atomic_fetch_add_explicit(&trace->playDataCount, 1,
|
atomic_fetch_add_explicit(&trace->playDataCount, 1,
|
||||||
|
|||||||
@@ -1486,13 +1486,15 @@ static void dispatchPlaybackData(LGMPAudio * audio,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t generation = audio->playback.generation.local;
|
const uint32_t generation =
|
||||||
const LG_AudioEventOps * events =
|
audio->playback.generation.local;
|
||||||
|
const LG_AudioEventOps * events =
|
||||||
audio->attached ? audio->events : NULL;
|
audio->attached ? audio->events : NULL;
|
||||||
void * opaque = audio->eventOpaque;
|
void * opaque = audio->eventOpaque;
|
||||||
const bool discontinuity = sequenceGap ||
|
const bool discontinuity = sequenceGap ||
|
||||||
audio->playbackDiscontinuity;
|
audio->playbackDiscontinuity ||
|
||||||
const bool clockValid =
|
(message->flags & KVMFR_AUDIO_MESSAGE_DISCONTINUITY) != 0;
|
||||||
|
const bool clockValid =
|
||||||
(message->flags & KVMFR_AUDIO_MESSAGE_CLOCK_VALID) != 0;
|
(message->flags & KVMFR_AUDIO_MESSAGE_CLOCK_VALID) != 0;
|
||||||
if (!events || !events->playbackData)
|
if (!events || !events->playbackData)
|
||||||
audio->playbackDiscontinuity = true;
|
audio->playbackDiscontinuity = true;
|
||||||
@@ -1506,7 +1508,7 @@ static void dispatchPlaybackData(LGMPAudio * audio,
|
|||||||
clockFromMessage(message, discontinuity);
|
clockFromMessage(message, discontinuity);
|
||||||
events->playbackData(opaque, generation,
|
events->playbackData(opaque, generation,
|
||||||
silent ? l_silence : payload, message->frames,
|
silent ? l_silence : payload, message->frames,
|
||||||
clockValid ? &clock : NULL);
|
clockValid ? &clock : NULL, discontinuity);
|
||||||
}
|
}
|
||||||
LG_UNLOCK(audio->eventLock);
|
LG_UNLOCK(audio->eventLock);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,6 @@
|
|||||||
#define NETWORK_AUDIO_CHANNEL_MASK UINT32_C(0x0003FFFF)
|
#define NETWORK_AUDIO_CHANNEL_MASK UINT32_C(0x0003FFFF)
|
||||||
#define NETWORK_AUDIO_PLAYBACK_STREAM_ID 1U
|
#define NETWORK_AUDIO_PLAYBACK_STREAM_ID 1U
|
||||||
#define NETWORK_AUDIO_CAPTURE_STREAM_ID 2U
|
#define NETWORK_AUDIO_CAPTURE_STREAM_ID 2U
|
||||||
#define NETWORK_AUDIO_CLOCK_CACHE_SIZE 16U
|
|
||||||
#define NETWORK_AUDIO_DATAGRAM_PAYLOAD 1136U
|
#define NETWORK_AUDIO_DATAGRAM_PAYLOAD 1136U
|
||||||
#define NETWORK_AUDIO_DATAGRAM_PCM_BYTES \
|
#define NETWORK_AUDIO_DATAGRAM_PCM_BYTES \
|
||||||
(NETWORK_AUDIO_DATAGRAM_PAYLOAD - LG_NET_AUDIO_DATA_HEADER_WIRE_SIZE)
|
(NETWORK_AUDIO_DATAGRAM_PAYLOAD - LG_NET_AUDIO_DATA_HEADER_WIRE_SIZE)
|
||||||
@@ -55,8 +54,7 @@
|
|||||||
(LG_NET_AUDIO_SUBSCRIBE_LOW_LATENCY | \
|
(LG_NET_AUDIO_SUBSCRIBE_LOW_LATENCY | \
|
||||||
LG_NET_AUDIO_SUBSCRIBE_EXCLUSIVE_CAPTURE | \
|
LG_NET_AUDIO_SUBSCRIBE_EXCLUSIVE_CAPTURE | \
|
||||||
LG_NET_AUDIO_SUBSCRIBE_CLOCK_FEEDBACK | \
|
LG_NET_AUDIO_SUBSCRIBE_CLOCK_FEEDBACK | \
|
||||||
LG_NET_AUDIO_SUBSCRIBE_DATAGRAM_PCM | \
|
LG_NET_AUDIO_SUBSCRIBE_DATAGRAM_PCM)
|
||||||
LG_NET_AUDIO_SUBSCRIBE_RELIABLE_PCM)
|
|
||||||
|
|
||||||
#define NETWORK_AUDIO_DIRECTIONS \
|
#define NETWORK_AUDIO_DIRECTIONS \
|
||||||
(LG_NET_AUDIO_DIRECTIONS_PLAYBACK | LG_NET_AUDIO_DIRECTIONS_CAPTURE)
|
(LG_NET_AUDIO_DIRECTIONS_PLAYBACK | LG_NET_AUDIO_DIRECTIONS_CAPTURE)
|
||||||
@@ -76,12 +74,6 @@ enum NetworkAudioPhase
|
|||||||
NETWORK_AUDIO_RELEASING,
|
NETWORK_AUDIO_RELEASING,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NetworkAudioClockEntry
|
|
||||||
{
|
|
||||||
bool valid;
|
|
||||||
LGNetAudioClockState state;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NetworkAudioStream
|
struct NetworkAudioStream
|
||||||
{
|
{
|
||||||
uint32_t streamID;
|
uint32_t streamID;
|
||||||
@@ -110,8 +102,6 @@ struct NetworkAudioStream
|
|||||||
bool packetKnown;
|
bool packetKnown;
|
||||||
uint64_t lastPacketID;
|
uint64_t lastPacketID;
|
||||||
bool discontinuity;
|
bool discontinuity;
|
||||||
unsigned clockInsert;
|
|
||||||
struct NetworkAudioClockEntry clocks[NETWORK_AUDIO_CLOCK_CACHE_SIZE];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NetworkAudio
|
struct NetworkAudio
|
||||||
@@ -463,12 +453,6 @@ static void networkAudioEndEvents(NetworkAudio * audio)
|
|||||||
LG_UNLOCK(audio->eventLock);
|
LG_UNLOCK(audio->eventLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void networkAudioClearClockNL(struct NetworkAudioStream * stream)
|
|
||||||
{
|
|
||||||
stream->clockInsert = 0;
|
|
||||||
memset(stream->clocks, 0, sizeof(stream->clocks));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void networkAudioClearStreamNL(struct NetworkAudioStream * stream)
|
static void networkAudioClearStreamNL(struct NetworkAudioStream * stream)
|
||||||
{
|
{
|
||||||
const uint32_t streamID = stream->streamID;
|
const uint32_t streamID = stream->streamID;
|
||||||
@@ -601,7 +585,7 @@ static LG_TransportStatus networkAudioSendDatagramNL(NetworkAudio * audio,
|
|||||||
{
|
{
|
||||||
return networkConnectionSendDatagram(audio->connection,
|
return networkConnectionSendDatagram(audio->connection,
|
||||||
LG_NET_SERVICE_AUDIO, messageType, audio->serviceVersion, 0,
|
LG_NET_SERVICE_AUDIO, messageType, audio->serviceVersion, 0,
|
||||||
audio->subscriptionEpoch, requestID, payload, payloadLength, 0, false);
|
audio->subscriptionEpoch, requestID, payload, payloadLength, 0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool networkAudioSendSubscribeNL(NetworkAudio * audio)
|
static bool networkAudioSendSubscribeNL(NetworkAudio * audio)
|
||||||
@@ -962,21 +946,12 @@ static void networkAudioDetach(void * opaque)
|
|||||||
LG_UNLOCK(audio->eventLock);
|
LG_UNLOCK(audio->eventLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool networkAudioSendClockAndDataNL(NetworkAudio * audio,
|
static LG_TransportStatus networkAudioSendPCMNL(NetworkAudio * audio,
|
||||||
const uint8_t * clockPayload, const uint8_t * dataPayload,
|
uint16_t messageType, const void * payload, uint32_t payloadLength)
|
||||||
uint32_t dataPayloadLength)
|
|
||||||
{
|
{
|
||||||
/* CLOCK_STATE and PCM are an ordered pair. Keep both on the same reliable
|
return (audio->grantedRoles & LG_NET_AUDIO_ROLE_DATAGRAM_PCM) ?
|
||||||
* stream until a future protocol version provides atomic datagram framing. */
|
networkAudioSendDatagramNL(audio, messageType, 0,
|
||||||
if (!(audio->grantedRoles & LG_NET_AUDIO_ROLE_RELIABLE_PCM))
|
payload, payloadLength) : LG_TRANSPORT_UNAVAILABLE;
|
||||||
return false;
|
|
||||||
|
|
||||||
return networkAudioSendReliableNL(audio,
|
|
||||||
LG_NET_AUDIO_MESSAGE_CLOCK_STATE, 0, 0, clockPayload,
|
|
||||||
LG_NET_AUDIO_CLOCK_STATE_WIRE_SIZE) == LG_TRANSPORT_OK &&
|
|
||||||
networkAudioSendReliableNL(audio,
|
|
||||||
LG_NET_AUDIO_MESSAGE_CAPTURE_DATA, 0, 0, dataPayload,
|
|
||||||
dataPayloadLength) == LG_TRANSPORT_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool networkAudioRecordData(void * opaque, uint32_t generation,
|
static bool networkAudioRecordData(void * opaque, uint32_t generation,
|
||||||
@@ -986,10 +961,9 @@ static bool networkAudioRecordData(void * opaque, uint32_t generation,
|
|||||||
if (!generation || !data || !frames)
|
if (!generation || !data || !frames)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint64_t rateQ32 = 0;
|
uint64_t rateQ32 = 0;
|
||||||
if (sourceClock &&
|
const bool sourceClockValid = sourceClock && sourceClock->time > 0 &&
|
||||||
!networkAudioRateQ32(sourceClock->rate, true, &rateQ32))
|
networkAudioRateQ32(sourceClock->rate, false, &rateQ32);
|
||||||
return false;
|
|
||||||
|
|
||||||
LG_LOCK(audio->stateLock);
|
LG_LOCK(audio->stateLock);
|
||||||
struct NetworkAudioStream * stream = &audio->capture;
|
struct NetworkAudioStream * stream = &audio->capture;
|
||||||
@@ -1044,11 +1018,11 @@ static bool networkAudioRecordData(void * opaque, uint32_t generation,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool result = true;
|
bool result = true;
|
||||||
bool discontinuity = stream->discontinuity ||
|
bool discontinuity = stream->discontinuity ||
|
||||||
(sourceClock && sourceClock->discontinuity);
|
(sourceClock && sourceClock->discontinuity);
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
const uint8_t * pcm = data;
|
const uint8_t * pcm = data;
|
||||||
while (offset < frames)
|
while (offset < frames)
|
||||||
{
|
{
|
||||||
size_t chunkFrames = frames - offset;
|
size_t chunkFrames = frames - offset;
|
||||||
@@ -1058,10 +1032,11 @@ static bool networkAudioRecordData(void * opaque, uint32_t generation,
|
|||||||
|
|
||||||
audio->capturePacketID = networkAudioNext64(audio->capturePacketID);
|
audio->capturePacketID = networkAudioNext64(audio->capturePacketID);
|
||||||
|
|
||||||
const uint64_t packetID = audio->capturePacketID;
|
const uint64_t packetID = audio->capturePacketID;
|
||||||
uint64_t position = firstPosition + offset;
|
const uint64_t position = firstPosition + offset;
|
||||||
int64_t timeNs = sourceClock ? sourceClock->time : 0;
|
int64_t timeNs = sourceClockValid ? sourceClock->time : 0;
|
||||||
if (sourceClock && offset)
|
bool clockValid = sourceClockValid;
|
||||||
|
if (clockValid && offset)
|
||||||
{
|
{
|
||||||
const long double elapsed =
|
const long double elapsed =
|
||||||
(long double)offset * 1000000000.0L /
|
(long double)offset * 1000000000.0L /
|
||||||
@@ -1070,29 +1045,13 @@ static bool networkAudioRecordData(void * opaque, uint32_t generation,
|
|||||||
if (adjusted >= (long double)INT64_MIN &&
|
if (adjusted >= (long double)INT64_MIN &&
|
||||||
adjusted <= (long double)INT64_MAX)
|
adjusted <= (long double)INT64_MAX)
|
||||||
timeNs = (int64_t)adjusted;
|
timeNs = (int64_t)adjusted;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clockValid = false;
|
||||||
|
timeNs = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
uint64_t timestampNs = timeNs > 0 ? (uint64_t)timeNs : nanotime();
|
LGNetAudioData packet =
|
||||||
if (!timestampNs)
|
|
||||||
timestampNs = 1;
|
|
||||||
|
|
||||||
const LGNetAudioClockState clock =
|
|
||||||
{
|
|
||||||
.streamID = stream->streamID,
|
|
||||||
.direction = stream->direction,
|
|
||||||
.flags = sourceClock ?
|
|
||||||
LG_NET_AUDIO_CLOCK_VALID |
|
|
||||||
(sourceClock->stable ? LG_NET_AUDIO_CLOCK_STABLE : 0) : 0,
|
|
||||||
.formatEpoch = stream->wireFormat.formatEpoch,
|
|
||||||
.subscriptionEpoch = audio->subscriptionEpoch,
|
|
||||||
.packetID = packetID,
|
|
||||||
.framePosition = position,
|
|
||||||
.timeNs = timeNs,
|
|
||||||
.rateQ32 = rateQ32,
|
|
||||||
.targetRateQ32 = 0,
|
|
||||||
.queuedFrames = 0,
|
|
||||||
.driftPpm = 0,
|
|
||||||
};
|
|
||||||
const LGNetAudioData packet =
|
|
||||||
{
|
{
|
||||||
.streamID = stream->streamID,
|
.streamID = stream->streamID,
|
||||||
.direction = stream->direction,
|
.direction = stream->direction,
|
||||||
@@ -1100,31 +1059,50 @@ static bool networkAudioRecordData(void * opaque, uint32_t generation,
|
|||||||
LG_NET_AUDIO_DATA_DISCONTINUITY : 0,
|
LG_NET_AUDIO_DATA_DISCONTINUITY : 0,
|
||||||
.formatEpoch = stream->wireFormat.formatEpoch,
|
.formatEpoch = stream->wireFormat.formatEpoch,
|
||||||
.packetID = packetID,
|
.packetID = packetID,
|
||||||
.timestampNs = timestampNs,
|
.timestampNs = timeNs > 0 ? (uint64_t)timeNs : 0,
|
||||||
.startFrame = position,
|
.startFrame = position,
|
||||||
|
.rateQ32 = clockValid ? rateQ32 : 0,
|
||||||
.frameCount = (uint32_t)chunkFrames,
|
.frameCount = (uint32_t)chunkFrames,
|
||||||
.dataLength = (uint32_t)chunkBytes,
|
.dataLength = (uint32_t)chunkBytes,
|
||||||
.data = pcm + offset * frameSize,
|
.data = pcm + offset * frameSize,
|
||||||
};
|
};
|
||||||
uint8_t clockPayload[LG_NET_AUDIO_CLOCK_STATE_WIRE_SIZE];
|
if (clockValid)
|
||||||
|
{
|
||||||
|
packet.flags |= LG_NET_AUDIO_DATA_CLOCK_VALID;
|
||||||
|
if (sourceClock->stable)
|
||||||
|
packet.flags |= LG_NET_AUDIO_DATA_CLOCK_STABLE;
|
||||||
|
}
|
||||||
|
|
||||||
const size_t dataPayloadLength =
|
const size_t dataPayloadLength =
|
||||||
LG_NET_AUDIO_DATA_HEADER_WIRE_SIZE + chunkBytes;
|
LG_NET_AUDIO_DATA_HEADER_WIRE_SIZE + chunkBytes;
|
||||||
if (!lgNetAudioClockStateEncode(clockPayload,
|
if (!lgNetAudioDataEncode(payload, dataPayloadLength, &packet))
|
||||||
sizeof(clockPayload), &clock) ||
|
|
||||||
!lgNetAudioDataEncode(payload, dataPayloadLength, &packet) ||
|
|
||||||
!networkAudioSendClockAndDataNL(audio, clockPayload, payload,
|
|
||||||
(uint32_t)dataPayloadLength))
|
|
||||||
{
|
{
|
||||||
result = false;
|
result = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
discontinuity = false;
|
const LG_TransportStatus status = networkAudioSendPCMNL(
|
||||||
|
audio, LG_NET_AUDIO_MESSAGE_CAPTURE_DATA,
|
||||||
|
payload, (uint32_t)dataPayloadLength);
|
||||||
|
if (status != LG_TRANSPORT_OK)
|
||||||
|
{
|
||||||
|
if (status == LG_TRANSPORT_UNAVAILABLE)
|
||||||
|
{
|
||||||
|
discontinuity = true;
|
||||||
|
offset += chunkFrames;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
discontinuity = false;
|
||||||
offset += chunkFrames;
|
offset += chunkFrames;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio->captureFramePosition = firstPosition + offset;
|
audio->captureFramePosition = firstPosition + offset;
|
||||||
stream->discontinuity = !result;
|
stream->discontinuity = discontinuity || !result;
|
||||||
free(payload);
|
free(payload);
|
||||||
LG_UNLOCK(audio->stateLock);
|
LG_UNLOCK(audio->stateLock);
|
||||||
return result;
|
return result;
|
||||||
@@ -1173,16 +1151,12 @@ static bool networkAudioClockFeedback(void * opaque, uint32_t generation,
|
|||||||
const bool encoded = lgNetAudioClockStateEncode(
|
const bool encoded = lgNetAudioClockStateEncode(
|
||||||
payload, sizeof(payload), &feedback);
|
payload, sizeof(payload), &feedback);
|
||||||
bool result = false;
|
bool result = false;
|
||||||
if (encoded &&
|
if (encoded)
|
||||||
(audio->grantedRoles & LG_NET_AUDIO_ROLE_DATAGRAM_PCM))
|
{
|
||||||
result = networkAudioSendDatagramNL(audio,
|
const LG_TransportStatus status = networkAudioSendDatagramNL(audio,
|
||||||
LG_NET_AUDIO_MESSAGE_CLOCK_STATE, 0,
|
LG_NET_AUDIO_MESSAGE_CLOCK_STATE, 0, payload, sizeof(payload));
|
||||||
payload, sizeof(payload)) == LG_TRANSPORT_OK;
|
result = status == LG_TRANSPORT_OK;
|
||||||
if (encoded && !result &&
|
}
|
||||||
(audio->grantedRoles & LG_NET_AUDIO_ROLE_RELIABLE_PCM))
|
|
||||||
result = networkAudioSendReliableNL(audio,
|
|
||||||
LG_NET_AUDIO_MESSAGE_CLOCK_STATE, 0, 0,
|
|
||||||
payload, sizeof(payload)) == LG_TRANSPORT_OK;
|
|
||||||
LG_UNLOCK(audio->stateLock);
|
LG_UNLOCK(audio->stateLock);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -1322,8 +1296,8 @@ static bool networkAudioHandleGrant(NetworkAudio * audio,
|
|||||||
if (!grant.maxPacketFrames ||
|
if (!grant.maxPacketFrames ||
|
||||||
(grant.grantedRoles & ~audio->requestedRoles) ||
|
(grant.grantedRoles & ~audio->requestedRoles) ||
|
||||||
grant.maxPacketFrames > NETWORK_AUDIO_MAX_PACKET_FRAMES ||
|
grant.maxPacketFrames > NETWORK_AUDIO_MAX_PACKET_FRAMES ||
|
||||||
(grant.grantedRoles & LG_NET_AUDIO_ROLE_DATAGRAM_PCM &&
|
!(grant.grantedRoles & LG_NET_AUDIO_ROLE_DATAGRAM_PCM) ||
|
||||||
!datagramAvailable) ||
|
!datagramAvailable ||
|
||||||
(grant.grantedRoles & LG_NET_AUDIO_ROLE_CAPTURE &&
|
(grant.grantedRoles & LG_NET_AUDIO_ROLE_CAPTURE &&
|
||||||
!(grant.grantedRoles & LG_NET_AUDIO_ROLE_EXCLUSIVE_CAPTURE)) ||
|
!(grant.grantedRoles & LG_NET_AUDIO_ROLE_EXCLUSIVE_CAPTURE)) ||
|
||||||
(grant.grantedRoles & LG_NET_AUDIO_ROLE_CLOCK_FEEDBACK &&
|
(grant.grantedRoles & LG_NET_AUDIO_ROLE_CLOCK_FEEDBACK &&
|
||||||
@@ -1430,7 +1404,6 @@ static bool networkAudioHandleStart(NetworkAudio * audio,
|
|||||||
stream->packetKnown = false;
|
stream->packetKnown = false;
|
||||||
stream->lastPacketID = 0;
|
stream->lastPacketID = 0;
|
||||||
stream->discontinuity = true;
|
stream->discontinuity = true;
|
||||||
networkAudioClearClockNL(stream);
|
|
||||||
networkAudioInvalidateBarrierNL(audio, stream);
|
networkAudioInvalidateBarrierNL(audio, stream);
|
||||||
const LG_AudioEventOps * events =
|
const LG_AudioEventOps * events =
|
||||||
audio->attached ? audio->events : NULL;
|
audio->attached ? audio->events : NULL;
|
||||||
@@ -1504,7 +1477,6 @@ static bool networkAudioHandleStop(NetworkAudio * audio,
|
|||||||
stream->volumeValid = false;
|
stream->volumeValid = false;
|
||||||
stream->muteValid = false;
|
stream->muteValid = false;
|
||||||
stream->discontinuity = true;
|
stream->discontinuity = true;
|
||||||
networkAudioClearClockNL(stream);
|
|
||||||
networkAudioInvalidateBarrierNL(audio, stream);
|
networkAudioInvalidateBarrierNL(audio, stream);
|
||||||
LG_UNLOCK(audio->stateLock);
|
LG_UNLOCK(audio->stateLock);
|
||||||
networkAudioCallEventsNL(audio);
|
networkAudioCallEventsNL(audio);
|
||||||
@@ -1774,7 +1746,6 @@ static bool networkAudioHandleStatus(NetworkAudio * audio,
|
|||||||
stream->volumeValid = false;
|
stream->volumeValid = false;
|
||||||
stream->muteValid = false;
|
stream->muteValid = false;
|
||||||
stream->discontinuity = true;
|
stream->discontinuity = true;
|
||||||
networkAudioClearClockNL(stream);
|
|
||||||
}
|
}
|
||||||
stream->stateSequence = state.stateSequence;
|
stream->stateSequence = state.stateSequence;
|
||||||
networkAudioInvalidateBarrierNL(audio, stream);
|
networkAudioInvalidateBarrierNL(audio, stream);
|
||||||
@@ -1861,62 +1832,6 @@ static bool networkAudioHandleBarrier(NetworkAudio * audio,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct NetworkAudioClockEntry * networkAudioFindClockNL(
|
|
||||||
struct NetworkAudioStream * stream, uint64_t packetID)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < NETWORK_AUDIO_CLOCK_CACHE_SIZE; ++i)
|
|
||||||
if (stream->clocks[i].valid &&
|
|
||||||
stream->clocks[i].state.packetID == packetID)
|
|
||||||
return &stream->clocks[i];
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool networkAudioHandleClock(NetworkAudio * audio,
|
|
||||||
const LGNetPacketView * packet)
|
|
||||||
{
|
|
||||||
LGNetAudioClockState state;
|
|
||||||
if (lgNetAudioClockStateDecode(&state,
|
|
||||||
packet->payload, packet->payloadLength) != LG_NET_PARSE_OK)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
LG_LOCK(audio->stateLock);
|
|
||||||
struct NetworkAudioStream * stream = networkAudioStreamNL(
|
|
||||||
audio, state.streamID, state.direction);
|
|
||||||
if (!stream || stream != &audio->playback)
|
|
||||||
{
|
|
||||||
LG_UNLOCK(audio->stateLock);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!networkAudioSubscriptionCurrentNL(audio, packet) ||
|
|
||||||
!networkAudioStreamRequiredNL(audio, stream) ||
|
|
||||||
state.subscriptionEpoch != audio->subscriptionEpoch)
|
|
||||||
{
|
|
||||||
LG_UNLOCK(audio->stateLock);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!stream->active || !stream->formatValid ||
|
|
||||||
state.formatEpoch != stream->wireFormat.formatEpoch ||
|
|
||||||
(stream->packetKnown && state.packetID <= stream->lastPacketID))
|
|
||||||
{
|
|
||||||
LG_UNLOCK(audio->stateLock);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct NetworkAudioClockEntry * entry = networkAudioFindClockNL(
|
|
||||||
stream, state.packetID);
|
|
||||||
if (!entry)
|
|
||||||
{
|
|
||||||
entry = &stream->clocks[
|
|
||||||
stream->clockInsert++ % NETWORK_AUDIO_CLOCK_CACHE_SIZE];
|
|
||||||
if (entry->valid)
|
|
||||||
stream->discontinuity = true;
|
|
||||||
}
|
|
||||||
entry->valid = true;
|
|
||||||
entry->state = state;
|
|
||||||
LG_UNLOCK(audio->stateLock);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool networkAudioHandlePlaybackData(NetworkAudio * audio,
|
static bool networkAudioHandlePlaybackData(NetworkAudio * audio,
|
||||||
const LGNetPacketView * packet)
|
const LGNetPacketView * packet)
|
||||||
{
|
{
|
||||||
@@ -1971,32 +1886,23 @@ static bool networkAudioHandlePlaybackData(NetworkAudio * audio,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NetworkAudioClockEntry * entry = networkAudioFindClockNL(
|
const bool discontinuity = stream->discontinuity || sequenceGap ||
|
||||||
stream, data.packetID);
|
(data.flags & LG_NET_AUDIO_DATA_DISCONTINUITY) != 0;
|
||||||
LG_AudioClock clock;
|
LG_AudioClock clock;
|
||||||
const LG_AudioClock * clockPtr = NULL;
|
const LG_AudioClock * clockPtr = NULL;
|
||||||
if (entry && (entry->state.flags & LG_NET_AUDIO_CLOCK_VALID))
|
if (data.flags & LG_NET_AUDIO_DATA_CLOCK_VALID)
|
||||||
{
|
{
|
||||||
clock = (LG_AudioClock)
|
clock = (LG_AudioClock)
|
||||||
{
|
{
|
||||||
.position = entry->state.framePosition,
|
.position = data.startFrame,
|
||||||
.time = entry->state.timeNs,
|
.time = (int64_t)data.timestampNs,
|
||||||
.rate = networkAudioRate(entry->state.rateQ32),
|
.rate = networkAudioRate(data.rateQ32),
|
||||||
.stable =
|
.stable =
|
||||||
(entry->state.flags & LG_NET_AUDIO_CLOCK_STABLE) != 0,
|
(data.flags & LG_NET_AUDIO_DATA_CLOCK_STABLE) != 0,
|
||||||
.discontinuity = stream->discontinuity || sequenceGap ||
|
.discontinuity = discontinuity,
|
||||||
(data.flags & LG_NET_AUDIO_DATA_DISCONTINUITY),
|
|
||||||
};
|
};
|
||||||
clockPtr = &clock;
|
clockPtr = &clock;
|
||||||
stream->discontinuity = false;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
stream->discontinuity = true;
|
|
||||||
if (entry)
|
|
||||||
entry->valid = false;
|
|
||||||
if (data.flags & LG_NET_AUDIO_DATA_END_OF_STREAM)
|
|
||||||
stream->discontinuity = true;
|
|
||||||
|
|
||||||
const size_t frameSize = (size_t)networkAudioSampleSize(
|
const size_t frameSize = (size_t)networkAudioSampleSize(
|
||||||
stream->wireFormat.sampleFormat) * stream->wireFormat.channels;
|
stream->wireFormat.sampleFormat) * stream->wireFormat.channels;
|
||||||
const size_t bytes = frameSize * data.frameCount;
|
const size_t bytes = frameSize * data.frameCount;
|
||||||
@@ -2013,11 +1919,13 @@ static bool networkAudioHandlePlaybackData(NetworkAudio * audio,
|
|||||||
const LG_AudioEventOps * events =
|
const LG_AudioEventOps * events =
|
||||||
audio->attached ? audio->events : NULL;
|
audio->attached ? audio->events : NULL;
|
||||||
void * opaque = audio->eventOpaque;
|
void * opaque = audio->eventOpaque;
|
||||||
|
stream->discontinuity = !events || !events->playbackData ||
|
||||||
|
(data.flags & LG_NET_AUDIO_DATA_END_OF_STREAM) != 0;
|
||||||
LG_UNLOCK(audio->stateLock);
|
LG_UNLOCK(audio->stateLock);
|
||||||
networkAudioCallEventsNL(audio);
|
networkAudioCallEventsNL(audio);
|
||||||
if (events && events->playbackData)
|
if (events && events->playbackData)
|
||||||
events->playbackData(opaque, generation, pcm,
|
events->playbackData(opaque, generation, pcm,
|
||||||
data.frameCount, clockPtr);
|
data.frameCount, clockPtr, discontinuity);
|
||||||
networkAudioEndEvents(audio);
|
networkAudioEndEvents(audio);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2078,7 +1986,7 @@ static bool networkAudioHandlePacket(NetworkAudio * audio,
|
|||||||
audio, packet, &audio->playback);
|
audio, packet, &audio->playback);
|
||||||
|
|
||||||
case LG_NET_AUDIO_MESSAGE_PLAYBACK_DATA:
|
case LG_NET_AUDIO_MESSAGE_PLAYBACK_DATA:
|
||||||
return networkAudioHandlePlaybackData(audio, packet);
|
return datagram && networkAudioHandlePlaybackData(audio, packet);
|
||||||
|
|
||||||
case LG_NET_AUDIO_MESSAGE_PLAYBACK_VOLUME:
|
case LG_NET_AUDIO_MESSAGE_PLAYBACK_VOLUME:
|
||||||
return !datagram && networkAudioHandleVolume(
|
return !datagram && networkAudioHandleVolume(
|
||||||
@@ -2107,9 +2015,6 @@ static bool networkAudioHandlePacket(NetworkAudio * audio,
|
|||||||
case LG_NET_AUDIO_MESSAGE_STATE_BARRIER:
|
case LG_NET_AUDIO_MESSAGE_STATE_BARRIER:
|
||||||
return !datagram && networkAudioHandleBarrier(audio, packet);
|
return !datagram && networkAudioHandleBarrier(audio, packet);
|
||||||
|
|
||||||
case LG_NET_AUDIO_MESSAGE_CLOCK_STATE:
|
|
||||||
return networkAudioHandleClock(audio, packet);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2149,7 +2054,6 @@ bool networkAudioCreate(NetworkAudio ** result,
|
|||||||
LG_NET_AUDIO_ROLE_CAPTURE |
|
LG_NET_AUDIO_ROLE_CAPTURE |
|
||||||
LG_NET_AUDIO_ROLE_CLOCK_FEEDBACK |
|
LG_NET_AUDIO_ROLE_CLOCK_FEEDBACK |
|
||||||
LG_NET_AUDIO_ROLE_DATAGRAM_PCM |
|
LG_NET_AUDIO_ROLE_DATAGRAM_PCM |
|
||||||
LG_NET_AUDIO_ROLE_RELIABLE_PCM |
|
|
||||||
LG_NET_AUDIO_ROLE_EXCLUSIVE_CAPTURE;
|
LG_NET_AUDIO_ROLE_EXCLUSIVE_CAPTURE;
|
||||||
audio->endpointGeneration = 1;
|
audio->endpointGeneration = 1;
|
||||||
audio->generationSerial = 1;
|
audio->generationSerial = 1;
|
||||||
@@ -2191,6 +2095,8 @@ void networkAudioConnectionState(NetworkAudio * audio, bool connected)
|
|||||||
const bool serviceAvailable = connected &&
|
const bool serviceAvailable = connected &&
|
||||||
networkConnectionServiceAvailable(audio->connection,
|
networkConnectionServiceAvailable(audio->connection,
|
||||||
LG_NET_SERVICE_AUDIO, LG_NET_CAPABILITY_RELIABLE) &&
|
LG_NET_SERVICE_AUDIO, LG_NET_CAPABILITY_RELIABLE) &&
|
||||||
|
networkConnectionServiceAvailable(audio->connection,
|
||||||
|
LG_NET_SERVICE_AUDIO, LG_NET_CAPABILITY_DATAGRAM) &&
|
||||||
networkConnectionServiceVersion(audio->connection,
|
networkConnectionServiceVersion(audio->connection,
|
||||||
LG_NET_SERVICE_AUDIO, &serviceVersion) &&
|
LG_NET_SERVICE_AUDIO, &serviceVersion) &&
|
||||||
networkAudioVersionSupported(serviceVersion);
|
networkAudioVersionSupported(serviceVersion);
|
||||||
|
|||||||
@@ -845,7 +845,7 @@ void spiceAudio_playbackData(SpiceAudio * audio,
|
|||||||
if (target.events->playbackData &&
|
if (target.events->playbackData &&
|
||||||
playbackEventCurrent(audio, &target, generation, true))
|
playbackEventCurrent(audio, &target, generation, true))
|
||||||
target.events->playbackData(target.opaque, generation,
|
target.events->playbackData(target.opaque, generation,
|
||||||
data, frames, &clock);
|
data, frames, &clock, false);
|
||||||
endEvent(audio);
|
endEvent(audio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ static void usbPlaybackData(
|
|||||||
{
|
{
|
||||||
const LG_AudioClock clock = makePlaybackClock(state, position);
|
const LG_AudioClock clock = makePlaybackClock(state, position);
|
||||||
events->playbackData(
|
events->playbackData(
|
||||||
target, generation, data, frames, &clock);
|
target, generation, data, frames, &clock, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
endCallback(&frame, &l_playbackFrames,
|
endCallback(&frame, &l_playbackFrames,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4747,13 +4747,18 @@ retry:
|
|||||||
HandshakeState handshake;
|
HandshakeState handshake;
|
||||||
uint64_t sessionEpoch;
|
uint64_t sessionEpoch;
|
||||||
uint32_t maxPayload;
|
uint32_t maxPayload;
|
||||||
|
bool closing;
|
||||||
{
|
{
|
||||||
CSRWSharedLock guard(connection.lock);
|
CSRWSharedLock guard(connection.lock);
|
||||||
handshake = connection.handshake;
|
handshake = connection.handshake;
|
||||||
sessionEpoch = connection.sessionEpoch;
|
sessionEpoch = connection.sessionEpoch;
|
||||||
maxPayload = connection.maxPayload;
|
maxPayload = connection.maxPayload;
|
||||||
|
closing = connection.closing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (closing)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (handshake == HandshakeState::WAITING_HELLO)
|
if (handshake == HandshakeState::WAITING_HELLO)
|
||||||
return packet.envelope.service == LG_NET_SERVICE_CORE &&
|
return packet.envelope.service == LG_NET_SERVICE_CORE &&
|
||||||
packet.envelope.messageType == LG_NET_CORE_MESSAGE_HELLO &&
|
packet.envelope.messageType == LG_NET_CORE_MESSAGE_HELLO &&
|
||||||
@@ -5188,6 +5193,8 @@ retry:
|
|||||||
const uint16_t serviceMask = UINT16_C(1) << packet.envelope.service;
|
const uint16_t serviceMask = UINT16_C(1) << packet.envelope.service;
|
||||||
{
|
{
|
||||||
CSRWExclusiveLock guard(connection.lock);
|
CSRWExclusiveLock guard(connection.lock);
|
||||||
|
if (connection.closing)
|
||||||
|
return true;
|
||||||
const bool serviceReady = packet.envelope.service ==
|
const bool serviceReady = packet.envelope.service ==
|
||||||
LG_NET_SERVICE_CORE ||
|
LG_NET_SERVICE_CORE ||
|
||||||
((connection.selectedServices & serviceMask) &&
|
((connection.selectedServices & serviceMask) &&
|
||||||
|
|||||||
Submodule repos/LGProtocol updated: 189c9bc5b6...a4a7519f47
Reference in New Issue
Block a user