Extensions to the audio HAL to send audio data to a ringbuffer inside

vsoc shared memory. Adds "record_audio" tool to sniff from the ringbuffer.

Change-Id: Iaa056a710ea42db2e17b69d33af7d389b77e955d
Bug: 72216799
Test: manually
diff --git a/Android.bp b/Android.bp
index 22d7ec9..124bc8a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -89,6 +89,8 @@
     name: "vsoc_lib",
     srcs: [
         "common/vsoc/lib/compat.cpp",
+        "common/vsoc/lib/audio_data_layout.cpp",
+        "common/vsoc/lib/audio_data_region_view.cpp",
         "common/vsoc/lib/e2e_test_region_layout.cpp",
         "common/vsoc/lib/fb_bcast_layout.cpp",
         "common/vsoc/lib/fb_bcast_region_view.cpp",
diff --git a/common/vsoc/lib/audio_data_layout.cpp b/common/vsoc/lib/audio_data_layout.cpp
new file mode 100644
index 0000000..4b5172c
--- /dev/null
+++ b/common/vsoc/lib/audio_data_layout.cpp
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+// Define some of the string constants associated with the region layout.
+#include "common/vsoc/shm/audio_data_layout.h"
+
+namespace vsoc {
+namespace layout {
+namespace audio_data {
+
+// static
+const char *const AudioDataLayout::region_name = "audio_data";
+
+}  // namespace audio_data
+}  // namespace layout
+}  // namespace vsoc
+
diff --git a/common/vsoc/lib/audio_data_region_view.cpp b/common/vsoc/lib/audio_data_region_view.cpp
new file mode 100644
index 0000000..868cc94
--- /dev/null
+++ b/common/vsoc/lib/audio_data_region_view.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#include "common/vsoc/lib/audio_data_region_view.h"
+
+#include "common/vsoc/lib/circqueue_impl.h"
+
+#include <mutex>
+
+using vsoc::layout::audio_data::AudioDataLayout;
+
+namespace vsoc {
+namespace audio_data {
+
+// static
+AudioDataRegionView *AudioDataRegionView::GetInstance() {
+    static AudioDataRegionView sInstance;
+    return &sInstance;
+}
+
+}  // namespace audio_data
+}  // namespace vsoc
+
diff --git a/common/vsoc/lib/audio_data_region_view.h b/common/vsoc/lib/audio_data_region_view.h
new file mode 100644
index 0000000..13e51f4
--- /dev/null
+++ b/common/vsoc/lib/audio_data_region_view.h
@@ -0,0 +1,40 @@
+#pragma once
+/*
+ * 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.
+ */
+
+#include <android-base/macros.h>
+
+#include "common/vsoc/lib/typed_region_view.h"
+#include "common/vsoc/shm/audio_data_layout.h"
+
+namespace vsoc {
+namespace audio_data {
+
+class AudioDataRegionView
+    : public vsoc::TypedRegionView<vsoc::layout::audio_data::AudioDataLayout> {
+public:
+    AudioDataRegionView(const AudioDataRegionView &) = delete;
+    AudioDataRegionView &operator=(const AudioDataRegionView &) = delete;
+
+    static AudioDataRegionView *GetInstance();
+
+private:
+    AudioDataRegionView() = default;
+};
+
+}  // namespace audio_data
+}  // namespace vsoc
+
diff --git a/common/vsoc/lib/circqueue_impl.h b/common/vsoc/lib/circqueue_impl.h
index 0abd7dd..dc65e4b 100644
--- a/common/vsoc/lib/circqueue_impl.h
+++ b/common/vsoc/lib/circqueue_impl.h
@@ -183,9 +183,27 @@
 intptr_t CircularPacketQueue<SizeLog2, MaxPacketSize>::Write(
     RegionSignalingInterface* r, const char* buffer_in, uint32_t bytes,
     bool non_blocking) {
+  iovec iov;
+  iov.iov_base = const_cast<char *>(buffer_in);
+  iov.iov_len = bytes;
+  return Writev(r, &iov, 1 /* iov_count */, non_blocking);
+}
+
+template <uint32_t SizeLog2, uint32_t MaxPacketSize>
+intptr_t CircularPacketQueue<SizeLog2, MaxPacketSize>::Writev(
+      RegionSignalingInterface *r,
+      const iovec *iov,
+      size_t iov_count,
+      bool non_blocking) {
+  size_t bytes = 0;
+  for (size_t i = 0; i < iov_count; ++i) {
+    bytes += iov[i].iov_len;
+  }
+
   if (bytes > MaxPacketSize) {
     return -ENOSPC;
   }
+
   Range range;
   size_t buffered_size = this->CalculateBufferedSize(bytes);
   this->lock_.Lock();
@@ -201,7 +219,15 @@
       static_cast<uint32_t>(range.start_idx + sizeof(uint32_t)),
       static_cast<uint32_t>(range.start_idx + sizeof(uint32_t) + bytes)};
   this->CopyInRange(reinterpret_cast<const char*>(&bytes), header);
-  this->CopyInRange(buffer_in, payload);
+
+  Range subRange = payload;
+  for (size_t i = 0; i < iov_count; ++i) {
+    subRange.end_idx = subRange.start_idx + iov[i].iov_len;
+    this->CopyInRange(static_cast<const char *>(iov[i].iov_base), subRange);
+
+    subRange.start_idx = subRange.end_idx;
+  }
+
   this->w_pub_ = range.end_idx;
   this->lock_.Unlock();
   layout::Sides side;
diff --git a/common/vsoc/shm/audio_data_layout.h b/common/vsoc/shm/audio_data_layout.h
new file mode 100644
index 0000000..d344a8e
--- /dev/null
+++ b/common/vsoc/shm/audio_data_layout.h
@@ -0,0 +1,39 @@
+#pragma once
+/*
+ * 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.
+ */
+
+#include "common/vsoc/shm/base.h"
+#include "common/vsoc/shm/circqueue.h"
+#include "common/vsoc/shm/version.h"
+
+// Memory layout for region carrying audio data from audio HAL to client.
+
+namespace vsoc {
+namespace layout {
+namespace audio_data {
+
+struct AudioDataLayout : public RegionLayout {
+    static const char *const region_name;
+
+    // size = 2^14 = 16384, packets are up to 4KB bytes each.
+    CircularPacketQueue<14, 4096> audio_queue;
+};
+ASSERT_SHM_COMPATIBLE(AudioDataLayout, audio_data);
+
+}  // namespace audio_data
+}  // namespace layout
+}  // namespace vsoc
+
diff --git a/common/vsoc/shm/circqueue.h b/common/vsoc/shm/circqueue.h
index 6e70c48..e841bbf 100644
--- a/common/vsoc/shm/circqueue.h
+++ b/common/vsoc/shm/circqueue.h
@@ -20,6 +20,7 @@
 
 #include <atomic>
 #include <cstdint>
+#include <sys/uio.h>
 
 #include "common/vsoc/shm/base.h"
 #include "common/vsoc/shm/lock.h"
@@ -154,6 +155,20 @@
   intptr_t Write(RegionSignalingInterface* r, const char* buffer_in,
                  uint32_t bytes, bool non_blocking = false);
 
+  /**
+   * Writes the data referenced by the given iov scatter/gather array to the
+   * queue.
+   * If the number of bytes to be written exceeds the size of the queue
+   * -ENOSPC will be returned.
+   * If non_blocking is true and there is not enough free space on the queue to
+   * write all the data -EWOULDBLOCK will be returned.
+   */
+  intptr_t Writev(
+          RegionSignalingInterface *r,
+          const iovec *iov,
+          size_t iov_count,
+          bool non_blocking = false);
+
  protected:
   static_assert(CircularQueueBase<SizeLog2>::BufferSize >= MaxPacketSize,
                 "Buffer is too small to hold the maximum sized packet");
diff --git a/common/vsoc/shm/version.h b/common/vsoc/shm/version.h
index c1a82e2..7a4e329 100644
--- a/common/vsoc/shm/version.h
+++ b/common/vsoc/shm/version.h
@@ -110,7 +110,7 @@
 const uint32_t version = 0;
 }
 // Three circular queues, each with a 1024 bytes buffer, a 32 bits spinlock and
-// two 32 bits inetgers
+// two 32 bits integers.
 static const std::size_t InputEventsLayout_size = 3 * (1024 + 3 * 4);
 }  // namespace input_events
 
@@ -161,6 +161,17 @@
 static const std::size_t E2EManagedTestRegionLayout_size = 4;
 }  // namespace e2e_test
 
+// Versioning information for audio_data_layout.h
+// Changes to these structures will affect only the audio_data region
+namespace audio_data {
+namespace {
+const uint32_t version = 0;
+}
+// One circular queue of with a 16KB buffer, a 32 bits spinlock and
+// two 32 bits integers.
+static const std::size_t AudioDataLayout_size = 16384 + 3 * 4;
+}  // namespace audio_data
+
 }  // namespace version_info
 }  // namespace layout
 }  // namespace vsoc
diff --git a/guest/hals/audio/Android.mk b/guest/hals/audio/Android.mk
index 7991395..28733ff 100644
--- a/guest/hals/audio/Android.mk
+++ b/guest/hals/audio/Android.mk
@@ -25,11 +25,13 @@
 LOCAL_MULTILIB := first
 
 LOCAL_SHARED_LIBRARIES := \
+    libbase \
     liblog \
     libcutils \
     cuttlefish_auto_resources \
     libcuttlefish_fs \
-    cuttlefish_time
+    cuttlefish_time \
+    vsoc_lib
 
 LOCAL_HEADER_LIBRARIES := \
     libhardware_headers
@@ -43,6 +45,7 @@
 
 LOCAL_C_INCLUDES := \
     device/google/cuttlefish_common \
+    device/google/cuttlefish_kernel \
     $(VSOC_STLPORT_INCLUDES) \
     frameworks/native/include/media/hardware \
     $(call include-path-for, audio)
@@ -65,3 +68,25 @@
 LOCAL_VENDOR_MODULE := true
 
 include $(BUILD_SHARED_LIBRARY)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := record_audio
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+    record_audio.cpp
+
+LOCAL_C_INCLUDES := \
+    device/google/cuttlefish_common \
+    device/google/cuttlefish_kernel \
+    frameworks/av/cmds/stagefright  \
+
+LOCAL_SHARED_LIBRARIES := \
+    libbase               \
+    vsoc_lib
+
+LOCAL_VENDOR_MODULE := true
+include $(BUILD_EXECUTABLE)
diff --git a/guest/hals/audio/record_audio.cpp b/guest/hals/audio/record_audio.cpp
new file mode 100644
index 0000000..6e9937d
--- /dev/null
+++ b/guest/hals/audio/record_audio.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+#include "vsoc_audio_message.h"
+
+#include "common/vsoc/lib/audio_data_region_view.h"
+#include "common/vsoc/lib/circqueue_impl.h"
+
+#include "WaveWriter.h"
+
+#include <cstdlib>
+#include <cstring>
+#include <iostream>
+#include <unistd.h>
+
+using AudioDataRegionView = vsoc::audio_data::AudioDataRegionView;
+using WaveWriter = android::WaveWriter;
+
+static void usage(const char *me) {
+  std::cerr << "usage: " << me << " -o filename [-v(erbose)]" << std::endl;
+  std::exit(1);
+}
+
+volatile bool gDone = false;
+static void SigIntHandler(int /* sig */) {
+  gDone = true;
+}
+
+int main(int argc, char **argv) {
+  const char *me = argv[0];
+
+  std::string outputPath;
+  bool verbose = false;
+
+  int res;
+  while ((res = getopt(argc, argv, "ho:v")) >= 0) {
+    switch (res) {
+      case 'o':
+      {
+        outputPath = optarg;
+        break;
+      }
+
+      case 'v' :
+      {
+        verbose = true;
+        break;
+      }
+
+      case '?':
+      case 'h':
+      default:
+      {
+        usage(me);
+        break;
+      }
+    }
+  }
+
+  argc -= optind;
+  argv += optind;
+
+  if (outputPath.empty()) {
+    usage(me);
+  }
+
+  AudioDataRegionView *audio_data_rv = AudioDataRegionView::GetInstance();
+  audio_data_rv->Open();
+
+  /* std::unique_ptr<vsoc::RegionWorker> audio_worker = */
+    audio_data_rv->StartWorker();
+
+  std::unique_ptr<WaveWriter> writer;
+  int64_t frameCount = 0ll;
+
+  // The configuration the writer is setup for.
+  gce_audio_message writer_hdr;
+
+  uint8_t buffer[4096];
+
+  gDone = false;
+
+  struct sigaction act;
+  sigemptyset(&act.sa_mask);
+  act.sa_flags = 0;
+  act.sa_handler = SigIntHandler;
+
+  struct sigaction oact;
+  sigaction(SIGINT, &act, &oact);
+
+  while (!gDone) {
+    intptr_t res = audio_data_rv->data()->audio_queue.Read(
+            audio_data_rv,
+            reinterpret_cast<char *>(buffer),
+            sizeof(buffer));
+
+    if (res < 0) {
+        std::cerr << "CircularPacketQueue::Read returned " << res << std::endl;
+        continue;
+    }
+
+    CHECK_GE(static_cast<size_t>(res), sizeof(gce_audio_message));
+
+    gce_audio_message hdr;
+    std::memcpy(&hdr, buffer, sizeof(gce_audio_message));
+
+    if (hdr.message_type != gce_audio_message::DATA_SAMPLES) {
+        continue;
+    }
+
+    const size_t payloadSize = res - sizeof(gce_audio_message);
+
+    if (verbose) {
+      std::cout
+          << "stream "
+          << hdr.stream_number
+          << ", frame "
+          << hdr.frame_num
+          << ", rate "
+          << hdr.frame_rate
+          << ", channel_mask "
+          << hdr.channel_mask
+          << ", format "
+          << hdr.format
+          << ", payload_size "
+          << payloadSize
+          << std::endl;
+    }
+
+    if (!writer) {
+      const size_t numChannels = hdr.frame_size / sizeof(int16_t);
+
+      writer.reset(
+          new WaveWriter(outputPath.c_str(), numChannels, hdr.frame_rate));
+
+      frameCount = hdr.frame_num;
+      writer_hdr = hdr;
+    } else if (writer_hdr.frame_size != hdr.frame_size
+        || writer_hdr.frame_rate != hdr.frame_rate
+        || writer_hdr.stream_number != hdr.stream_number) {
+      std::cerr << "Audio configuration changed. Aborting." << std::endl;
+      break;
+    }
+
+    int64_t framesMissing = hdr.frame_num - frameCount;
+    if (framesMissing > 0) {
+      // TODO(andih): Insert silence here, if necessary.
+    }
+
+    frameCount = hdr.frame_num;
+
+    writer->Append(&buffer[sizeof(gce_audio_message)], payloadSize);
+  }
+
+  std::cout << "Done." << std::endl;
+
+  return 0;
+}
diff --git a/guest/hals/audio/vsoc_audio.cpp b/guest/hals/audio/vsoc_audio.cpp
index cfd7017..67ff28f 100644
--- a/guest/hals/audio/vsoc_audio.cpp
+++ b/guest/hals/audio/vsoc_audio.cpp
@@ -15,6 +15,7 @@
  */
 #include "guest/hals/audio/audio_hal.h"
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/time.h>
@@ -28,6 +29,7 @@
 #include "common/libs/fs/shared_select.h"
 #include "common/libs/threads/cuttlefish_thread.h"
 #include "common/libs/threads/thunkers.h"
+#include "common/vsoc/lib/circqueue_impl.h"
 #include "guest/hals/audio/vsoc_audio.h"
 #include "guest/hals/audio/vsoc_audio_input_stream.h"
 #include "guest/hals/audio/vsoc_audio_output_stream.h"
@@ -63,22 +65,10 @@
       delete it->second;
     }
   }
-  // Make certain that the listener thread wakes up
-  cvd::SharedFD temp_client =
-      cvd::SharedFD::SocketSeqPacketClient(
-          gce_audio_message::kAudioHALSocketName);
-  uint64_t dummy_val = 1;
-  terminate_listener_thread_event_->Write(&dummy_val, sizeof dummy_val);
-  pthread_join(listener_thread_, NULL);
   delete this;
   return 0;
 }
 
-cvd::SharedFD GceAudio::GetAudioFd() {
-  LockGuard<Mutex> guard(lock_);
-  return audio_data_socket_;
-}
-
 size_t GceAudio::GetInputBufferSize(const audio_config*) const {
   return IN_BUFFER_BYTES;
 }
@@ -223,12 +213,20 @@
   return 0;
 }
 
-ssize_t GceAudio::SendMsg(const msghdr& msg, int flags) {
-  cvd::SharedFD fd = GetAudioFd();
-  if (!fd->IsOpen()) {
-    return 0;
-  }
-  return fd->SendMsg(&msg, flags);
+ssize_t GceAudio::SendMsg(const msghdr& msg, int /* flags */) {
+    intptr_t res = audio_data_rv_->data()->audio_queue.Writev(
+            audio_data_rv_,
+            msg.msg_iov,
+            msg.msg_iovlen,
+            true /* non_blocking */);
+
+    if (res < 0) {
+        ALOGV("GceAudio::%s: CircularPacketQueue::Write returned %" PRIiPTR,
+              __FUNCTION__,
+              res);
+    }
+
+    return static_cast<ssize_t>(res);
 }
 
 ssize_t GceAudio::SendStreamUpdate(
@@ -283,94 +281,6 @@
   return 0;
 }
 
-void* GceAudio::Listener() {
-  // TODO(ghartman): Consider tightening the mode on this later.
-  audio_listener_socket_ = cvd::SharedFD::SocketSeqPacketServer(
-      gce_audio_message::kAudioHALSocketName, 0777);
-  if (!audio_listener_socket_->IsOpen()) {
-    ALOGE("GceAudio::%s: Could not listen for audio connections. (%s).",
-          __FUNCTION__, audio_listener_socket_->StrError());
-    return NULL;
-  }
-  ALOGI("GceAudio::%s: Listening for audio connections at %s",
-        __FUNCTION__, gce_audio_message::kAudioHALSocketName);
-  remoter_request_packet announce;
-  remoter_request_packet_init(&announce, kRemoterHALReady, 0);
-  announce.send_response = 0;
-  strncpy(announce.params.hal_ready_params.unix_socket,
-          gce_audio_message::kAudioHALSocketName,
-          sizeof(announce.params.hal_ready_params.unix_socket));
-  AutoCloseFileDescriptor remoter_socket(remoter_connect());
-  if (remoter_socket.IsError()) {
-    ALOGI("GceAudio::%s: Couldn't connect to remoter to register HAL (%s).",
-          __FUNCTION__, strerror(errno));
-  } else {
-    int err = remoter_do_single_request_with_socket(
-        remoter_socket, &announce, NULL);
-    if (err == -1) {
-      ALOGI("GceAudio::%s: HAL registration failed after connect (%s).",
-            __FUNCTION__, strerror(errno));
-    } else {
-      ALOGI("GceAudio::%s: HAL registered with the remoter", __FUNCTION__);
-    }
-  }
-  while (true) {
-    // Poll for new connections or the terminatation event.
-    // The listener is non-blocking. We send to at most one client. If a new
-    // client comes in disconnect the old one.
-    cvd::SharedFDSet fd_set;
-    fd_set.Set(audio_listener_socket_);
-    fd_set.Set(terminate_listener_thread_event_);
-    if (cvd::Select(&fd_set, NULL, NULL, NULL) <= 0) {
-      // There's no timeout, so 0 shouldn't happen.
-      ALOGE("GceAudio::%s: Error using shared Select", __FUNCTION__);
-      break;
-    }
-    if (fd_set.IsSet(terminate_listener_thread_event_)) {
-      break;
-    }
-    LOG_FATAL_IF(fd_set.IsSet(audio_listener_socket_),
-                 "No error in Select() but nothing ready to read");
-    cvd::SharedFD fd = cvd::SharedFD::Accept(
-        *audio_listener_socket_);
-    if (!fd->IsOpen()) {
-      continue;
-    }
-    std::list<gce_audio_message> streams;
-    {
-      LockGuard<Mutex> guard(lock_);
-      // Do not do I/O while holding the lock. It could block the HAL
-      // implementation.
-      // Register the fd before dropping the lock to ensure that every
-      // active stream will appear when we first connect.
-      // Some output streams may appear twice if an open is active
-      // during the connect.
-      audio_data_socket_ = fd;
-      for (std::list<GceAudioOutputStream*>::iterator it = output_list_.begin();
-           it != output_list_.end(); ++it) {
-        streams.push_back((*it)->GetStreamDescriptor(
-            gce_audio_message::OPEN_OUTPUT_STREAM));
-      }
-      for (input_map_t::iterator it = input_map_.begin();
-           it != input_map_.end(); ++it) {
-        streams.push_back(it->second->GetStreamDescriptor(
-            it->first, gce_audio_message::OPEN_INPUT_STREAM));
-      }
-    }
-    for (std::list<gce_audio_message>::iterator it = streams.begin();
-         it != streams.end(); ++it) {
-      // We're willing to block because this is independent of the HAL
-      // implementation. We also don't want to forget to mention the input
-      // streams.
-      if (SendStreamUpdate(*it, 0) < 0) {
-        ALOGE("GceAudio::%s: Failed to announce open stream (%s)",
-              __FUNCTION__, fd->StrError());
-      }
-    }
-  }
-  return NULL;
-}
-
 int GceAudio::Open(const hw_module_t* module, const char* name,
                    hw_device_t** device) {
   D("GceAudio::%s", __FUNCTION__);
@@ -382,13 +292,11 @@
   }
 
   GceAudio* rval = new GceAudio;
-  int err = pthread_create(
-      &rval->listener_thread_, NULL,
-      AudioThreadThunker<void*()>::call<&GceAudio::Listener>, rval);
-  if (err) {
-    ALOGE("GceAudio::%s: Unable to start listener thread (%s)", __FUNCTION__,
-          strerror(err));
-  }
+
+  rval->audio_data_rv_ = AudioDataRegionView::GetInstance();
+  rval->audio_data_rv_->Open();
+  rval->audio_worker_ = rval->audio_data_rv_->StartWorker();
+
   rval->common.tag = HARDWARE_DEVICE_TAG;
   rval->common.version = version_;
   rval->common.module = const_cast<hw_module_t *>(module);
diff --git a/guest/hals/audio/vsoc_audio.h b/guest/hals/audio/vsoc_audio.h
index 4022888..6a6e0e6 100644
--- a/guest/hals/audio/vsoc_audio.h
+++ b/guest/hals/audio/vsoc_audio.h
@@ -20,6 +20,7 @@
 
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/threads/cuttlefish_thread.h"
+#include "common/vsoc/lib/audio_data_region_view.h"
 #include "guest/hals/audio/audio_hal.h"
 #include "guest/hals/audio/vsoc_audio_input_stream.h"
 #include "guest/hals/audio/vsoc_audio_message.h"
@@ -46,10 +47,6 @@
     return mic_muted_;
   }
 
-  // Retrieves the SharedFD of the process accepting audio data.
-  // Returns a non-open fd if no process is listening (the normal case).
-  cvd::SharedFD GetAudioFd();
-
   // Send a message to the connected streamer.
   // Returns:
   //   0 if there is no streamer.
@@ -211,8 +208,6 @@
 
 
  private:
-  // Main routine for a thread that listens for incoming streamer connections.
-  void* Listener();
   // HAL 3.0 modifies the signatures of OpenInputStream and OpenOutputStream.
   // We don't want to fork the implementation, and we don't want #ifdefs all
   // over the code. The current implementation defines OpenInputStream and
@@ -270,19 +265,12 @@
   static const unsigned int version_ = AUDIO_DEVICE_API_VERSION_1_0;
 #endif
 
-  // Thread to handle new connections.
-  pthread_t listener_thread_;
-  // Event to indicate that the listener thread should terminate.
-  cvd::SharedFD terminate_listener_thread_event_;
-  // The listener socket, which is polled for new connections.
-  // TODO(ghartman): Consider using a thread.
-  cvd::SharedFD audio_listener_socket_;
+  using AudioDataRegionView = vsoc::audio_data::AudioDataRegionView;
+  AudioDataRegionView *audio_data_rv_ = NULL;
+  std::unique_ptr<vsoc::RegionWorker> audio_worker_;
+
   // Lock to protect the data below.
   mutable cvd::Mutex lock_;
-  // The data socket for the current streamer. Typically -1.
-  // The behavior of the HAL should not be affected by the presence or absence
-  // of the streamer.
-  cvd::SharedFD audio_data_socket_;
   // State that is managed at the device level.
   float voice_volume_;
   float master_volume_;
@@ -307,7 +295,6 @@
 
   GceAudio() :
       audio_hw_device(),
-      terminate_listener_thread_event_(cvd::SharedFD::Event()),
       voice_volume_(0.0),
       master_volume_(0.0),
       master_muted_(false),
diff --git a/host/config/vsoc_mem.json b/host/config/vsoc_mem.json
index 7cdb794..f9cbc36 100644
--- a/host/config/vsoc_mem.json
+++ b/host/config/vsoc_mem.json
@@ -206,6 +206,23 @@
     "host_to_guest_signal_table" : {
       "num_nodes_lg2" : 1
     }
+   },
+
+   {
+     "device_name" : "audio_data",
+     "__comment" : "Write audio HAL output data to ringbuffer",
+     "current_version" : 0,
+     "min_compatible_version" : 0,
+     "region_size": 20480,
+
+     "guest_to_host_signal_table" : {
+       "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
+       "num_nodes_lg2" : 2
+      },
+
+     "host_to_guest_signal_table" : {
+       "num_nodes_lg2" : 2
+      }
    }
   ]
 }