[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/livekit/client-sdk-cpp/main/src/platform_audio.cpp [Back]  [Original]

/*
 * Copyright 2026 LiveKit
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "livekit/platform_audio.h"

#include 

#include "ffi.pb.h"
#include "ffi_client.h"

namespace livekit {

struct PlatformAudioState {
  FfiHandle handle;
};

namespace {

std::uint64_t requireHandle(const std::shared_ptr& state) {
  if (!state || !state->handle) {
    throw PlatformAudioError("PlatformAudio has no valid FFI handle");
  }
  return static_cast(state->handle.get());
}

AudioDeviceInfo fromProto(const proto::AudioDeviceInfo& device) {
  AudioDeviceInfo out;
  out.index = device.index();
  out.name = device.name();
  out.id = device.has_guid() ? device.guid() : std::string();
  return out;
}

std::vector convertDevices(const google::protobuf::RepeatedPtrField& devices) {
  std::vector out;
  out.reserve(static_cast(devices.size()));
  for (const auto& device : devices) {
    out.push_back(fromProto(device));
  }
  return out;
}

proto::AudioSourceOptions toProto(const PlatformAudioOptions& options) {
  proto::AudioSourceOptions out;
  out.set_echo_cancellation(options.echo_cancellation);
  out.set_noise_suppression(options.noise_suppression);
  out.set_auto_gain_control(options.auto_gain_control);
  out.set_prefer_hardware(options.prefer_hardware);
  return out;
}

proto::GetAudioDevicesResponse getAudioDevices(const std::shared_ptr& state) {
  proto::FfiRequest req;
  req.mutable_get_audio_devices()->set_platform_audio_handle(requireHandle(state));

  const proto::FfiResponse resp = FfiClient::instance().sendRequest(req);
  if (!resp.has_get_audio_devices()) {
    throw PlatformAudioError("FfiResponse missing get_audio_devices");
  }

  const auto& devices = resp.get_audio_devices();
  if (devices.has_error() && !devices.error().empty()) {
    throw PlatformAudioError(devices.error());
  }
  return devices;
}

} // namespace

PlatformAudioSource::PlatformAudioSource(FfiHandle handle, std::shared_ptr platform_audio) noexcept
    : handle_(std::move(handle)), platform_audio_(std::move(platform_audio)) {}

PlatformAudio::PlatformAudio() {
  proto::FfiRequest req;
  req.mutable_new_platform_audio();

  const proto::FfiResponse resp = FfiClient::instance().sendRequest(req);
  if (!resp.has_new_platform_audio()) {
    throw PlatformAudioError("Failed to construct PlatformAudio: FfiResponse missing new_platform_audio");
  }

  const auto& platform_audio = resp.new_platform_audio();
  if (platform_audio.has_error()) {
    throw PlatformAudioError(platform_audio.error());
  }
  if (!platform_audio.has_platform_audio()) {
    throw PlatformAudioError("Failed to construct PlatformAudio: NewPlatformAudioResponse missing platform_audio");
  }

  const auto& owned = platform_audio.platform_audio();
  state_ = std::make_shared();
  state_->handle = FfiHandle(static_cast(owned.handle().id()));
}

std::int32_t PlatformAudio::recordingDeviceCount() const {
  return static_cast(getAudioDevices(state_).recording_devices_size());
}

std::int32_t PlatformAudio::playoutDeviceCount() const {
  return static_cast(getAudioDevices(state_).playout_devices_size());
}

std::vector PlatformAudio::recordingDevices() const {
  return convertDevices(getAudioDevices(state_).recording_devices());
}

std::vector PlatformAudio::playoutDevices() const {
  return convertDevices(getAudioDevices(state_).playout_devices());
}

void PlatformAudio::setRecordingDevice(const std::string& device_id) const {
  proto::FfiRequest req;
  auto* msg = req.mutable_set_recording_device();
  msg->set_platform_audio_handle(requireHandle(state_));
  msg->set_device_id(device_id);

  const proto::FfiResponse resp = FfiClient::instance().sendRequest(req);
  if (!resp.has_set_recording_device()) {
    throw PlatformAudioError("FfiResponse missing set_recording_device");
  }

  const auto& set_device = resp.set_recording_device();
  if (set_device.has_error() && !set_device.error().empty()) {
    throw PlatformAudioError(set_device.error());
  }
}

void PlatformAudio::setPlayoutDevice(const std::string& device_id) const {
  proto::FfiRequest req;
  auto* msg = req.mutable_set_playout_device();
  msg->set_platform_audio_handle(requireHandle(state_));
  msg->set_device_id(device_id);

  const proto::FfiResponse resp = FfiClient::instance().sendRequest(req);
  if (!resp.has_set_playout_device()) {
    throw PlatformAudioError("FfiResponse missing set_playout_device");
  }

  const auto& set_device = resp.set_playout_device();
  if (set_device.has_error() && !set_device.error().empty()) {
    throw PlatformAudioError(set_device.error());
  }
}

std::shared_ptr PlatformAudio::createAudioSource(const PlatformAudioOptions& options) const {
  proto::FfiRequest req;
  auto* msg = req.mutable_new_audio_source();
  msg->set_type(proto::AudioSourceType::AUDIO_SOURCE_PLATFORM);
  msg->set_platform_audio_handle(requireHandle(state_));
  *msg->mutable_options() = toProto(options);

  const proto::FfiResponse resp = FfiClient::instance().sendRequest(req);
  if (!resp.has_new_audio_source()) {
    throw PlatformAudioError("FfiResponse missing new_audio_source");
  }

  const auto& new_source = resp.new_audio_source();
  if (!new_source.has_source() || !new_source.source().has_handle()) {
    throw PlatformAudioError("NewAudioSourceResponse missing source handle");
  }

  const auto& source = new_source.source();
  const std::uint64_t handle_id = source.handle().id();
  if (handle_id == 0) {
    throw PlatformAudioError("NewAudioSourceResponse returned an invalid (null) source handle");
  }

  FfiHandle handle(static_cast(handle_id));
  return std::shared_ptr(new PlatformAudioSource(std::move(handle), state_));
}

} // namespace livekit

Web Proxy Viewer  |  New URL  |  Original Page