Revert deleting vsoc

Bug: 144973127
Test: git diff 698c8df9e00602c8cd82bbcc872693509a169fe9
Change-Id: I19d15f093a69e18f6fafa00e4808620297d37df8
diff --git a/host/frontend/Android.bp b/host/frontend/Android.bp
index 8d78a9f..5a053e7 100644
--- a/host/frontend/Android.bp
+++ b/host/frontend/Android.bp
@@ -14,6 +14,7 @@
 // limitations under the License.
 
 subdirs = [
+    "stream_audio",
     "vnc_server",
     "adb_connector",
 ]
diff --git a/host/frontend/stream_audio/Android.bp b/host/frontend/stream_audio/Android.bp
new file mode 100644
index 0000000..8f07536
--- /dev/null
+++ b/host/frontend/stream_audio/Android.bp
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// 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.
+
+cc_binary_host {
+    name: "stream_audio",
+    srcs: [
+        "main.cpp",
+    ],
+    shared_libs: [
+        "cuttlefish_tcp_socket",
+        "libbase",
+        "libcuttlefish_utils",
+        "libcuttlefish_fs",
+        "libopus",
+        "vsoc_lib",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libjsoncpp",
+        "libgflags",
+        "libopuscpp",
+    ],
+    cpp_std: "c++17",
+    enabled: false,
+    defaults: ["cuttlefish_host_only"],
+}
diff --git a/host/frontend/stream_audio/main.cpp b/host/frontend/stream_audio/main.cpp
new file mode 100644
index 0000000..f63e315
--- /dev/null
+++ b/host/frontend/stream_audio/main.cpp
@@ -0,0 +1,270 @@
+/*
+ *
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * 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.
+ */
+
+// For each client that connects initially a header is sent with the following,
+// in this order, all as uint16_t in network-byte-order:
+//  number of channels, frame rate
+//
+// Following, audio packets are sent as a uint32_t length (network byte order)
+// indicating the number of bytes
+// followed by the (opus) frame_size as a uint32_t
+// followed by <length> bytes.
+
+#include "common/libs/tcp_socket/tcp_socket.h"
+#include "common/vsoc/lib/audio_data_region_view.h"
+#include "common/vsoc/lib/circqueue_impl.h"
+#include "common/vsoc/lib/vsoc_audio_message.h"
+#include "host/frontend/stream_audio/opuscpp/opus_wrapper.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+#include <android-base/logging.h>
+#include <gflags/gflags.h>
+
+#include <arpa/inet.h>
+
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <tuple>
+#include <vector>
+
+using vsoc::audio_data::AudioDataRegionView;
+
+DEFINE_int32(port, 0, "port on which to serve audio.");
+
+namespace {
+
+// Read audio frames from the AudioDataRegionView
+class AudioStreamer {
+ public:
+  cvd::Message MakeAudioDescriptionHeader() const {
+    std::unique_lock guard(buffer_lock_);
+    while (!audio_buffer_) {
+      buffer_cv_.wait(guard);
+    }
+
+    const size_t num_channels = header_.frame_size / sizeof(opus_int16);
+    return cvd::CreateMessage(static_cast<std::uint16_t>(num_channels),
+                              static_cast<std::uint16_t>(header_.frame_rate));
+  }
+
+  std::uint32_t frame_rate() const {
+    std::unique_lock guard(buffer_lock_);
+    while (!audio_buffer_) {
+      buffer_cv_.wait(guard);
+    }
+    return header_.frame_rate;
+  }
+
+  std::uint32_t num_channels() const {
+    std::unique_lock guard(buffer_lock_);
+    while (!audio_buffer_) {
+      buffer_cv_.wait(guard);
+    }
+    return header_.frame_size / sizeof(opus_int16);
+  }
+
+  // Returns the frame id and audio frame
+  std::tuple<std::int64_t, std::shared_ptr<const cvd::Message>> audio_buffer(
+      std::int64_t previous_frame_num) const {
+    std::unique_lock guard(buffer_lock_);
+    while (header_.frame_num <= previous_frame_num) {
+      buffer_cv_.wait(guard);
+    }
+
+    return {header_.frame_num, audio_buffer_};
+  }
+
+  void Update() {
+    auto audio_data_rv =
+        AudioDataRegionView::GetInstance(vsoc::GetDomain().c_str());
+    auto worker = audio_data_rv->StartWorker();
+    std::vector<char> new_buffer;
+
+    while (true) {
+      new_buffer.resize(new_buffer.capacity());
+
+      auto [new_header, payload_size, audio_data] =
+          NextAudioMessage(audio_data_rv, &new_buffer);
+
+      LOG(DEBUG) << "stream " << new_header.stream_number << ", frame "
+                 << new_header.frame_num << ", rate " << new_header.frame_rate
+                 << ", channel_mask " << new_header.channel_mask << ", format "
+                 << new_header.format << ", payload_size " << payload_size
+                 << '\n';
+
+      {
+        std::lock_guard guard(buffer_lock_);
+        CheckAudioConfigurationIsSame(new_header);
+        header_ = new_header;
+        audio_buffer_ = std::make_shared<const cvd::Message>(
+            audio_data, audio_data + payload_size);
+      }
+      buffer_cv_.notify_all();
+    }
+  }
+
+ private:
+  struct AudioMessage {
+    gce_audio_message header;
+    std::size_t payload_size;
+    const std::uint8_t* payload_data;
+  };
+
+  void ReadAudioMessage(AudioDataRegionView* audio_data_rv,
+                        std::vector<char>* buffer) const {
+    while (true) {
+      auto read_size = audio_data_rv->data()->audio_queue.Read(
+          audio_data_rv, buffer->data(), buffer->size());
+      if (read_size == -ENOSPC) {
+        DoubleSize(buffer);
+      } else if (read_size < 0) {
+        LOG(ERROR) << "CircularPacketQueue::Read returned " << read_size;
+      } else {
+        buffer->resize(read_size);
+        return;
+      }
+    }
+  }
+
+  void DoubleSize(std::vector<char>* buffer) const {
+    if (buffer->empty()) {
+      buffer->resize(1);
+    } else {
+      buffer->resize(buffer->size() * 2);
+    }
+  }
+
+  gce_audio_message GetHeaderFromBuffer(const std::vector<char>& buffer) const {
+    gce_audio_message new_header{};
+    CHECK_GE(buffer.size(), sizeof new_header);
+
+    std::memcpy(&new_header, buffer.data(), sizeof new_header);
+    CHECK_GT(new_header.stream_number, 0u);
+    return new_header;
+  }
+
+  std::tuple<std::size_t, const std::uint8_t*> GetPayloadFromBuffer(
+      const std::vector<char>& buffer) const {
+    const auto payload_size = buffer.size() - sizeof(gce_audio_message);
+    const auto* audio_data =
+        reinterpret_cast<const std::uint8_t*>(buffer.data()) +
+        sizeof(gce_audio_message);
+    return {payload_size, audio_data};
+  }
+
+  AudioMessage NextAudioMessage(AudioDataRegionView* audio_data_rv,
+                                std::vector<char>* buffer) const {
+    while (true) {
+      ReadAudioMessage(audio_data_rv, buffer);
+      auto header = GetHeaderFromBuffer(*buffer);
+      if (header.message_type == gce_audio_message::DATA_SAMPLES) {
+        auto [payload_size, payload_data] = GetPayloadFromBuffer(*buffer);
+        return {header, payload_size, payload_data};
+      }
+    }
+  }
+
+  void CheckAudioConfigurationIsSame(
+      const gce_audio_message& new_header) const {
+    if (audio_buffer_) {
+      CHECK_EQ(header_.frame_size, new_header.frame_size)
+          << "audio frame_size changed";
+      CHECK_EQ(header_.frame_rate, new_header.frame_rate)
+          << "audio frame_rate changed";
+      CHECK_EQ(header_.stream_number, new_header.stream_number)
+          << "audio stream_number changed";
+    }
+  }
+
+  std::shared_ptr<const cvd::Message> audio_buffer_{};
+  gce_audio_message header_{};
+  mutable std::mutex buffer_lock_;
+  mutable std::condition_variable buffer_cv_;
+};
+
+void HandleClient(AudioStreamer* audio_streamer,
+                  cvd::ClientSocket client_socket) {
+  auto num_channels = audio_streamer->num_channels();
+  opus::Encoder enc(audio_streamer->frame_rate(),
+                    audio_streamer->num_channels(), OPUS_APPLICATION_AUDIO);
+  CHECK(enc.valid()) << "Could not construct Encoder. Maybe bad frame_rate ("
+                     << audio_streamer->frame_rate() <<") or num_channels ("
+                     << audio_streamer->num_channels() << ")?";
+
+  auto header = audio_streamer->MakeAudioDescriptionHeader();
+  client_socket.SendNoSignal(header);
+  std::int64_t previous_frame_num = 0;
+
+  while (!client_socket.closed()) {
+    CHECK(enc.valid()) << "encoder in invalid state";
+    auto [frame_num, audio_data] =
+        audio_streamer->audio_buffer(previous_frame_num);
+    previous_frame_num = frame_num;
+
+    std::vector<opus_int16> pcm(audio_data->size() / sizeof(opus_int16));
+    std::memcpy(pcm.data(), audio_data->data(), audio_data->size());
+    // in opus terms "frame_size" is the number of unencoded samples per frame
+    const std::uint32_t frame_size = pcm.size() / num_channels;
+    auto encoded = enc.Encode(pcm, frame_size);
+    for (auto&& p : encoded) {
+      auto length_message =
+          cvd::CreateMessage(static_cast<std::uint32_t>(p.size()));
+      client_socket.SendNoSignal(length_message);
+      client_socket.SendNoSignal(cvd::CreateMessage(frame_size));
+      client_socket.SendNoSignal(p);
+    }
+  }
+}
+
+[[noreturn]] void AudioStreamerUpdateLoop(AudioStreamer* audio_streamer) {
+  while (true) {
+    audio_streamer->Update();
+  }
+}
+
+[[noreturn]] void MainLoop() {
+  AudioStreamer audio_streamer;
+  std::thread audio_streamer_update_thread;
+  auto server = cvd::ServerSocket(FLAGS_port);
+  while (true) {
+    LOG(INFO) << "waiting for client connection";
+    auto client = server.Accept();
+    LOG(INFO) << "client socket accepted";
+    if (!audio_streamer_update_thread.joinable()) {
+      audio_streamer_update_thread =
+          std::thread{AudioStreamerUpdateLoop, &audio_streamer};
+    }
+    std::thread(HandleClient, &audio_streamer, std::move(client)).detach();
+  }
+}
+
+}  // namespace
+
+int main(int argc, char* argv[]) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  gflags::SetUsageMessage(" ");
+  google::ParseCommandLineFlags(&argc, &argv, true);
+  if (FLAGS_port <= 0) {
+    std::cerr << "--port must be specified.\n";
+    return 1;
+  }
+  MainLoop();
+}
diff --git a/host/frontend/stream_audio/opuscpp/Android.bp b/host/frontend/stream_audio/opuscpp/Android.bp
new file mode 100644
index 0000000..9ad7a52
--- /dev/null
+++ b/host/frontend/stream_audio/opuscpp/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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.
+
+cc_library_host_static {
+    name: "libopuscpp",
+    srcs: [
+        "opus_wrapper.cc",
+    ],
+    shared_libs: [
+        "libbase",
+        "libopus",
+    ],
+    cpp_std: "c++17",
+    enabled: false,
+    defaults: ["cuttlefish_host_only"],
+}
diff --git a/host/frontend/stream_audio/opuscpp/opus_wrapper.cc b/host/frontend/stream_audio/opuscpp/opus_wrapper.cc
new file mode 100644
index 0000000..538bee8
--- /dev/null
+++ b/host/frontend/stream_audio/opuscpp/opus_wrapper.cc
@@ -0,0 +1,177 @@
+// Copyright 2018 Google LLC
+//
+// 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
+//
+//     https://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.
+
+// https://github.com/google/opuscpp
+
+#include <iterator>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <android-base/logging.h>
+#include "host/frontend/stream_audio/opuscpp/opus_wrapper.h"
+
+std::string opus::ErrorToString(int error) {
+  switch (error) {
+    case OPUS_OK:
+      return "OK";
+    case OPUS_BAD_ARG:
+      return "One or more invalid/out of range arguments.";
+    case OPUS_BUFFER_TOO_SMALL:
+      return "The mode struct passed is invalid.";
+    case OPUS_INTERNAL_ERROR:
+      return "An internal error was detected.";
+    case OPUS_INVALID_PACKET:
+      return "The compressed data passed is corrupted.";
+    case OPUS_UNIMPLEMENTED:
+      return "Invalid/unsupported request number.";
+    case OPUS_INVALID_STATE:
+      return "An encoder or decoder structure is invalid or already freed.";
+    default:
+      return "Unknown error code: " + std::to_string(error);
+  }
+}
+
+void opus::internal::OpusDestroyer::operator()(OpusEncoder* encoder) const
+    noexcept {
+  opus_encoder_destroy(encoder);
+}
+
+void opus::internal::OpusDestroyer::operator()(OpusDecoder* decoder) const
+    noexcept {
+  opus_decoder_destroy(decoder);
+}
+
+opus::Encoder::Encoder(opus_int32 sample_rate, int num_channels,
+                       int application, int expected_loss_percent)
+    : num_channels_{num_channels} {
+  int error{};
+  encoder_.reset(
+      opus_encoder_create(sample_rate, num_channels, application, &error));
+  valid_ = error == OPUS_OK;
+  if (!valid()) {
+    LOG(INFO) << "Could not construct encoder. Error: " << ErrorToString(error);
+    return;
+  }
+  if (expected_loss_percent > 0) {
+    LOG(INFO) << "Enabling FEC in the encoder.";
+    Ctl(OPUS_SET_INBAND_FEC(1));
+    Ctl(OPUS_SET_PACKET_LOSS_PERC(expected_loss_percent));
+  }
+}
+
+bool opus::Encoder::ResetState() {
+  valid_ = Ctl(OPUS_RESET_STATE) == OPUS_OK;
+  return valid_;
+}
+
+bool opus::Encoder::SetBitrate(int bitrate) {
+  valid_ = Ctl(OPUS_SET_BITRATE(bitrate)) == OPUS_OK;
+  return valid_;
+}
+
+bool opus::Encoder::SetVariableBitrate(int vbr) {
+  valid_ = Ctl(OPUS_SET_VBR(vbr)) == OPUS_OK;
+  return valid_;
+}
+
+bool opus::Encoder::SetComplexity(int complexity) {
+  valid_ = Ctl(OPUS_SET_COMPLEXITY(complexity)) == OPUS_OK;
+  return valid_;
+}
+
+int opus::Encoder::GetLookahead() {
+  opus_int32 skip{};
+  valid_ = Ctl(OPUS_GET_LOOKAHEAD(&skip)) == OPUS_OK;
+  return skip;
+}
+
+std::vector<std::vector<unsigned char>> opus::Encoder::Encode(
+    const std::vector<opus_int16>& pcm, int frame_size) {
+  constexpr auto sample_size = sizeof(pcm[0]);
+  const auto frame_length = frame_size * num_channels_ * sample_size;
+  auto data_length = pcm.size() * sample_size;
+  if (data_length % frame_length != 0u) {
+    LOG(WARNING) << "PCM samples contain an incomplete frame. Ignoring the "
+                    "incomplete frame.";
+    data_length -= (data_length % frame_length);
+  }
+
+  std::vector<std::vector<unsigned char>> encoded;
+  for (std::size_t i{}; i < data_length; i += frame_length) {
+    encoded.push_back(EncodeFrame(pcm.begin() + (i / sample_size), frame_size));
+  }
+  return encoded;
+}
+
+std::vector<unsigned char> opus::Encoder::EncodeFrame(
+    const std::vector<opus_int16>::const_iterator& frame_start,
+    int frame_size) {
+  const auto frame_length = (frame_size * num_channels_ * sizeof(*frame_start));
+  std::vector<unsigned char> encoded(frame_length);
+  auto num_bytes = opus_encode(encoder_.get(), &*frame_start, frame_size,
+                               encoded.data(), encoded.size());
+  if (num_bytes < 0) {
+    LOG(ERROR) << "Encode error: " << opus::ErrorToString(num_bytes);
+    return {};
+  }
+  encoded.resize(num_bytes);
+  return encoded;
+}
+
+opus::Decoder::Decoder(opus_uint32 sample_rate, int num_channels)
+    : num_channels_(num_channels) {
+  int error{};
+  decoder_.reset(opus_decoder_create(sample_rate, num_channels, &error));
+  valid_ = error == OPUS_OK;
+}
+
+std::vector<opus_int16> opus::Decoder::Decode(
+    const std::vector<std::vector<unsigned char>>& packets, int frame_size,
+    bool decode_fec) {
+  std::vector<opus_int16> decoded;
+  for (const auto& enc : packets) {
+    auto just_decoded = Decode(enc, frame_size, decode_fec);
+    decoded.insert(std::end(decoded), std::begin(just_decoded),
+                   std::end(just_decoded));
+  }
+  return decoded;
+}
+
+std::vector<opus_int16> opus::Decoder::Decode(
+    const std::vector<unsigned char>& packet, int frame_size, bool decode_fec) {
+  const auto frame_length = (frame_size * num_channels_ * sizeof(opus_int16));
+  std::vector<opus_int16> decoded(frame_length);
+  auto num_samples = opus_decode(decoder_.get(), packet.data(), packet.size(),
+                                 decoded.data(), frame_size, decode_fec);
+  if (num_samples < 0) {
+    LOG(ERROR) << "Decode error: " << opus::ErrorToString(num_samples);
+    return {};
+  }
+  decoded.resize(num_samples * num_channels_);
+  return decoded;
+}
+
+std::vector<opus_int16> opus::Decoder::DecodeDummy(int frame_size) {
+  const auto frame_length = (frame_size * num_channels_ * sizeof(opus_int16));
+  std::vector<opus_int16> decoded(frame_length);
+  auto num_samples =
+      opus_decode(decoder_.get(), nullptr, 0, decoded.data(), frame_size, true);
+  if (num_samples < 0) {
+    LOG(ERROR) << "Decode error: " << opus::ErrorToString(num_samples);
+    return {};
+  }
+  decoded.resize(num_samples * num_channels_);
+  return decoded;
+}
diff --git a/host/frontend/stream_audio/opuscpp/opus_wrapper.h b/host/frontend/stream_audio/opuscpp/opus_wrapper.h
new file mode 100644
index 0000000..07e932e
--- /dev/null
+++ b/host/frontend/stream_audio/opuscpp/opus_wrapper.h
@@ -0,0 +1,133 @@
+// Copyright 2018 Google LLC
+//
+// 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
+//
+//     https://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.
+
+// https://github.com/google/opuscpp
+
+#ifndef OPUSCPP_OPUS_WRAPPER_H_
+#define OPUSCPP_OPUS_WRAPPER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "opus.h"
+
+namespace opus {
+
+std::string ErrorToString(int error);
+
+namespace internal {
+// Deleter for OpusEncoders and OpusDecoders
+struct OpusDestroyer {
+  void operator()(OpusEncoder* encoder) const noexcept;
+  void operator()(OpusDecoder* decoder) const noexcept;
+};
+template <typename T>
+using opus_uptr = std::unique_ptr<T, OpusDestroyer>;
+}  // namespace internal
+
+class Encoder {
+ public:
+  // see documentation at:
+  // https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__encoder.html#gaa89264fd93c9da70362a0c9b96b9ca88
+  // Fs corresponds to sample_rate
+  //
+  // If expected_loss_percent is positive, FEC will be enabled
+  Encoder(opus_int32 sample_rate, int num_channels, int application,
+          int expected_loss_percent = 0);
+
+  // Resets internal state of encoder. This should be called between encoding
+  // different streams so that back-to-back decoding and one-at-a-time decoding
+  // give the same result. Returns true on success.
+  bool ResetState();
+
+  // Sets the desired bitrate. Rates from 500 to 512000 are meaningful as well
+  // as the special values OPUS_AUTO and OPUS_BITRATE_MAX. If this method
+  // is not called, the default value of OPUS_AUTO is used.
+  // Returns true on success.
+  bool SetBitrate(int bitrate);
+
+  // Enables or disables variable bitrate in the encoder. By default, variable
+  // bitrate is enabled. Returns true on success.
+  bool SetVariableBitrate(int vbr);
+
+  // Sets the computational complexity of the encoder, in the range of 0 to 10,
+  // inclusive, with 10 being the highest complexity. Returns true on success.
+  bool SetComplexity(int complexity);
+
+  // Gets the total samples of delay added by the entire codec. This value
+  // is the minimum amount of 'preskip' that has to be specified in an
+  // ogg-stream that encapsulates the encoded audio.
+  int GetLookahead();
+
+  // Takes audio data and encodes it. Returns a sequence of encoded packets.
+  // pcm.size() must be divisible by frame_size * (number of channels);
+  // pcm must not contain any incomplete packets.
+  // see documentation for pcm and frame_size at:
+  // https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__encoder.html#gad2d6bf6a9ffb6674879d7605ed073e25
+  std::vector<std::vector<unsigned char>> Encode(
+      const std::vector<opus_int16>& pcm, int frame_size);
+
+  int valid() const { return valid_; }
+
+ private:
+  std::vector<unsigned char> EncodeFrame(
+      const std::vector<opus_int16>::const_iterator& frame_start,
+      int frame_size);
+
+  template <typename... Ts>
+  int Ctl(int request, Ts... args) const {
+    return opus_encoder_ctl(encoder_.get(), request, args...);
+  }
+
+  int num_channels_{};
+  bool valid_{};
+  internal::opus_uptr<OpusEncoder> encoder_;
+};
+
+class Decoder {
+ public:
+  // see documentation at:
+  // https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__decoder.html#ga753f6fe0b699c81cfd47d70c8e15a0bd
+  // Fs corresponds to sample_rate
+  Decoder(opus_uint32 sample_rate, int num_channels);
+
+  // Takes a sequence of encoded packets and decodes them. Returns the decoded
+  // audio.
+  // see documentation at:
+  // https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__decoder.html#ga7d1111f64c36027ddcb81799df9b3fc9
+  std::vector<opus_int16> Decode(
+      const std::vector<std::vector<unsigned char>>& packets, int frame_size,
+      bool decode_fec);
+
+  int valid() const { return valid_; }
+
+  // Takes an encoded packet and decodes it. Returns the decoded audio
+  // see documentation at:
+  // https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/group__opus__decoder.html#ga7d1111f64c36027ddcb81799df9b3fc9
+  std::vector<opus_int16> Decode(const std::vector<unsigned char>& packet,
+                                 int frame_size, bool decode_fec);
+
+  // Generates a dummy frame by passing nullptr to the underlying opus decode.
+  std::vector<opus_int16> DecodeDummy(int frame_size);
+
+ private:
+  int num_channels_{};
+  bool valid_{};
+  internal::opus_uptr<OpusDecoder> decoder_;
+};
+
+}  // namespace opus
+
+#endif
diff --git a/host/frontend/vnc_server/Android.bp b/host/frontend/vnc_server/Android.bp
index 210f21d..fae5a17 100644
--- a/host/frontend/vnc_server/Android.bp
+++ b/host/frontend/vnc_server/Android.bp
@@ -30,6 +30,7 @@
         "cuttlefish_glog",
     ],
     shared_libs: [
+        "vsoc_lib",
         "libcuttlefish_fs",
         "libcuttlefish_utils",
         "cuttlefish_tcp_socket",
diff --git a/host/frontend/vnc_server/screen_connector.cpp b/host/frontend/vnc_server/screen_connector.cpp
index 35cf22f..53cb389 100644
--- a/host/frontend/vnc_server/screen_connector.cpp
+++ b/host/frontend/vnc_server/screen_connector.cpp
@@ -18,11 +18,11 @@
 
 #include <atomic>
 #include <condition_variable>
-#include <thread>
 
-#include <glog/logging.h>
 #include <gflags/gflags.h>
 
+#include <common/vsoc/lib/screen_region_view.h>
+#include <host/libs/config/cuttlefish_config.h>
 #include "host/frontend/vnc_server/vnc_utils.h"
 
 DEFINE_int32(frame_server_fd, -1, "");
@@ -31,6 +31,23 @@
 namespace vnc {
 
 namespace {
+class VSoCScreenConnector : public ScreenConnector {
+ public:
+  int WaitForNewFrameSince(std::uint32_t* seq_num) override {
+    if (!screen_view_) return -1;
+    return screen_view_->WaitForNewFrameSince(seq_num);
+  }
+
+  void* GetBuffer(int buffer_idx) override {
+    if (!screen_view_) return nullptr;
+    return screen_view_->GetBuffer(buffer_idx);
+  }
+
+ private:
+  vsoc::screen::ScreenRegionView* screen_view_ =
+      vsoc::screen::ScreenRegionView::GetInstance(vsoc::GetDomain().c_str());
+};
+
 // TODO(b/128852363): Substitute with one based on memory shared with the
 //  wayland mock
 class SocketBasedScreenConnector : public ScreenConnector {
@@ -123,7 +140,12 @@
 }  // namespace
 
 ScreenConnector* ScreenConnector::Get() {
-  return new SocketBasedScreenConnector();
+  auto config = vsoc::CuttlefishConfig::Get();
+  if (config->enable_ivserver()) {
+    return new VSoCScreenConnector();
+  } else {
+    return new SocketBasedScreenConnector();
+  }
 }
 
 }  // namespace vnc
diff --git a/host/frontend/vnc_server/simulated_hw_composer.cpp b/host/frontend/vnc_server/simulated_hw_composer.cpp
index 96702e8..7a94454 100644
--- a/host/frontend/vnc_server/simulated_hw_composer.cpp
+++ b/host/frontend/vnc_server/simulated_hw_composer.cpp
@@ -20,6 +20,7 @@
 #include "host/libs/config/cuttlefish_config.h"
 
 using cvd::vnc::SimulatedHWComposer;
+using vsoc::screen::ScreenRegionView;
 
 SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb)
     :
diff --git a/host/frontend/vnc_server/virtual_inputs.cpp b/host/frontend/vnc_server/virtual_inputs.cpp
index fb91409..31c0328 100644
--- a/host/frontend/vnc_server/virtual_inputs.cpp
+++ b/host/frontend/vnc_server/virtual_inputs.cpp
@@ -16,19 +16,18 @@
 
 #include "host/frontend/vnc_server/virtual_inputs.h"
 #include <gflags/gflags.h>
-#include <glog/logging.h>
 #include <linux/input.h>
 #include <linux/uinput.h>
 
 #include <cstdint>
 #include <mutex>
-#include <thread>
 #include "keysyms.h"
 
 #include <common/libs/fs/shared_select.h>
 #include <host/libs/config/cuttlefish_config.h>
 
 using cvd::vnc::VirtualInputs;
+using vsoc::input_events::InputEventsRegionView;
 
 DEFINE_int32(touch_fd, -1,
              "A fd for a socket where to accept touch connections");
@@ -246,6 +245,37 @@
 
 }  // namespace
 
+class VSoCVirtualInputs : public VirtualInputs {
+ public:
+  VSoCVirtualInputs()
+      : input_events_region_view_{
+            vsoc::input_events::InputEventsRegionView::GetInstance(
+                vsoc::GetDomain().c_str())} {
+    if (!input_events_region_view_) {
+      LOG(FATAL) << "Failed to open Input events region view";
+    }
+  }
+
+  void GenerateKeyPressEvent(int code, bool down) override {
+    if (keymapping_.count(code)) {
+      input_events_region_view_->HandleKeyboardEvent(down, keymapping_[code]);
+    } else {
+      LOG(ERROR) << "Unknown keycode" << code;
+    }
+  }
+
+  void PressPowerButton(bool down) override {
+    input_events_region_view_->HandlePowerButtonEvent(down);
+  }
+
+  void HandlePointerEvent(bool touch_down, int x, int y) override {
+    input_events_region_view_->HandleSingleTouchEvent(touch_down, x, y);
+  }
+
+ private:
+  vsoc::input_events::InputEventsRegionView* input_events_region_view_{};
+};
+
 class SocketVirtualInputs : public VirtualInputs {
  public:
   SocketVirtualInputs()
diff --git a/host/frontend/vnc_server/virtual_inputs.h b/host/frontend/vnc_server/virtual_inputs.h
index 7aca3eb..f92693b 100644
--- a/host/frontend/vnc_server/virtual_inputs.h
+++ b/host/frontend/vnc_server/virtual_inputs.h
@@ -21,6 +21,8 @@
 #include <map>
 #include <mutex>
 
+#include "common/vsoc/lib/input_events_region_view.h"
+
 namespace cvd {
 namespace vnc {
 
diff --git a/host/frontend/vnc_server/vnc_client_connection.cpp b/host/frontend/vnc_server/vnc_client_connection.cpp
index b81bb88..a8faf47 100644
--- a/host/frontend/vnc_server/vnc_client_connection.cpp
+++ b/host/frontend/vnc_server/vnc_client_connection.cpp
@@ -42,17 +42,7 @@
 using cvd::vnc::Stripe;
 using cvd::vnc::StripePtrVec;
 using cvd::vnc::VncClientConnection;
-
-struct ScreenRegionView {
-  using Pixel = uint32_t;
-  static constexpr int kSwiftShaderPadding = 4;
-  static constexpr int kRedShift = 0;
-  static constexpr int kGreenShift = 8;
-  static constexpr int kBlueShift = 16;
-  static constexpr int kRedBits = 8;
-  static constexpr int kGreenBits = 8;
-  static constexpr int kBlueBits = 8;
-};
+using vsoc::screen::ScreenRegionView;
 
 DEFINE_bool(debug_client, false, "Turn on detailed logging for the client");
 
diff --git a/host/frontend/vnc_server/vnc_utils.h b/host/frontend/vnc_server/vnc_utils.h
index db88131..0953c4e 100644
--- a/host/frontend/vnc_server/vnc_utils.h
+++ b/host/frontend/vnc_server/vnc_utils.h
@@ -23,6 +23,7 @@
 
 #include "common/libs/utils/size_utils.h"
 #include "common/libs/tcp_socket/tcp_socket.h"
+#include "common/vsoc/lib/screen_region_view.h"
 #include "host/libs/config/cuttlefish_config.h"
 
 namespace cvd {
@@ -64,7 +65,7 @@
 };
 
 inline constexpr int BytesPerPixel() {
-  return sizeof(uint32_t);
+  return sizeof(vsoc::screen::ScreenRegionView::Pixel);
 }
 
 // The width of the screen regardless of orientation. Does not change.