sendAudioData method

Future<void> sendAudioData({
  1. required List<String> agents,
  2. String topic = dataTopic,
})

Sends the currently buffered audio to one or more agent identities.

This is a one shot operation. Repeated calls are ignored after the buffer has been sent.

The stream is written to topic (default: dataTopic) and includes attributes that help the agent interpret the raw audio payload.

Implementation

Future<void> sendAudioData({
  required List<String> agents,
  String topic = dataTopic,
}) async {
  if (_isBufferSent) return;
  if (agents.isEmpty) return;

  final sampleRate = _renderedSampleRate;
  final rawChannels = _renderedChannels ?? 1;
  final channels = rawChannels > 0 ? rawChannels : 1;
  if (sampleRate == null) {
    logger.severe('[Preconnect audio] renderedSampleRate is null');
    return;
  }
  if (rawChannels <= 0) {
    logger.warning('[Preconnect audio] Invalid rendered channels: $rawChannels. Falling back to mono.');
  }

  // Wait for local track published event
  final localTrackPublishedEvent = await _localTrackPublishedEvent;
  logger.info('[Preconnect audio] localTrackPublishedEvent: $localTrackPublishedEvent');

  final localTrackSid = localTrackPublishedEvent?.publication.track?.sid;
  if (localTrackSid == null) {
    logger.severe('[Preconnect audio] localTrackPublishedEvent is null');
    return;
  }

  logger.info('[Preconnect audio] sending audio data to ${agents.map((e) => e).join(', ')} agent(s)');

  final data = _buffer.takeBytes();
  logger.info('[Preconnect audio] data.length: ${data.length}, bytes.length: ${_buffer.length}');

  _isBufferSent = true;

  final streamOptions = StreamBytesOptions(
    topic: topic,
    attributes: {
      'sampleRate': sampleRate.toString(),
      'channels': channels.toString(),
      'commonFormat': 'int16',
      'trackId': localTrackSid,
    },
    totalSize: data.length,
    destinationIdentities: agents,
  );

  logger.info('[Preconnect audio] streamOptions: $streamOptions');

  final writer = await _room.localParticipant!.streamBytes(streamOptions);
  await writer.write(data);
  await writer.close();

  // Compute seconds of audio data sent
  final int bytesPerSample = 2; // 16-bit audio
  final int bytesPerFrame = bytesPerSample * channels;
  final int totalFrames = data.length ~/ bytesPerFrame;
  final double secondsOfAudio = totalFrames / sampleRate;

  logger.info(
      '[Preconnect audio] sent ${(data.length / 1024).toStringAsFixed(1)}KB of audio (${secondsOfAudio.toStringAsFixed(2)} seconds) to ${agents} agent(s)');
}