diff --git a/repos/ports/lib/mk/virtualbox5-common.inc b/repos/ports/lib/mk/virtualbox5-common.inc
index b48ad2fa47..0cc5861e19 100644
--- a/repos/ports/lib/mk/virtualbox5-common.inc
+++ b/repos/ports/lib/mk/virtualbox5-common.inc
@@ -55,6 +55,8 @@ VBOX_CC_OPT += -DVBOX_WITH_E1000
VBOX_CC_OPT += -DVBOX_WITH_AHCI
VBOX_CC_OPT += -DVBOX_WITH_MULTI_CORE
+VBOX_CC_OPT += -DVBOX_WITH_AUDIO_OSS
+
VIRTUALBOX_VERSION_MAJOR := $(shell cat $(VIRTUALBOX_DIR)/Config.kmk 2>/dev/null | grep "VBOX_VERSION_MAJOR = " | grep -v "'VBOX_VERSION_MAJOR" | sed "s/^.*= //")
VIRTUALBOX_VERSION_MINOR := $(shell cat $(VIRTUALBOX_DIR)/Config.kmk 2>/dev/null | grep "VBOX_VERSION_MINOR = " | grep -v "'VBOX_VERSION_MINOR" | sed "s/^.*= //")
VIRTUALBOX_VERSION_BUILD := $(shell cat $(VIRTUALBOX_DIR)/Config.kmk 2>/dev/null | grep "VBOX_VERSION_BUILD = " | grep -v "'VBOX_VERSION_BUILD" | sed "s/^.*= //")
diff --git a/repos/ports/lib/mk/virtualbox5-drivers.mk b/repos/ports/lib/mk/virtualbox5-drivers.mk
index fa6526727d..90365b8211 100644
--- a/repos/ports/lib/mk/virtualbox5-drivers.mk
+++ b/repos/ports/lib/mk/virtualbox5-drivers.mk
@@ -17,10 +17,10 @@ SRC_CC += Devices/Serial/DrvHostSerial.cpp
SRC_CC += Devices/Audio/DrvAudio.cpp
SRC_CC += Devices/Audio/DrvHostNullAudio.cpp
-#SRC_CC += audiodrv.cpp
SRC_CC += network.cpp
+SRC_CC += audio.cc
INC_DIR += $(VBOX_DIR)/Devices/Audio
-#vpath audiodrv.cpp $(REP_DIR)/src/virtualbox
vpath network.cpp $(REP_DIR)/src/virtualbox
+vpath audio.cc $(REP_DIR)/src/virtualbox5
diff --git a/repos/ports/run/vm_win7_64.vbox b/repos/ports/run/vm_win7_64.vbox
index c4c59b663d..89780f3a4a 100644
--- a/repos/ports/run/vm_win7_64.vbox
+++ b/repos/ports/run/vm_win7_64.vbox
@@ -72,7 +72,7 @@
-
+
diff --git a/repos/ports/src/virtualbox/libc.cc b/repos/ports/src/virtualbox/libc.cc
index 5feff63d46..fb4133d648 100644
--- a/repos/ports/src/virtualbox/libc.cc
+++ b/repos/ports/src/virtualbox/libc.cc
@@ -19,7 +19,6 @@
/* libc includes */
#include
#include
-#include
#include /* statfs */
#include
#include
@@ -162,6 +161,9 @@ extern "C" char *getenv(const char *name)
// "+shared_folders.e.l.f"
// "+drv_host_serial.e.l.f"
// "+dev_audio.e.l.f"
+// "+dev_hda.e"
+// "+drv_host_audio.e.l.f"
+// "+drv_audio.e.l.f"
;
if (Genode::strcmp(name, "VBOX_LOG_FLAGS") == 0 ||
@@ -185,17 +187,6 @@ extern "C" int sigaction(int signum, const struct sigaction *act,
}
-/* our libc provides a _nanosleep function */
-extern "C" int _nanosleep(const struct timespec *req, struct timespec *rem);
-extern "C" int nanosleep(const struct timespec *req, struct timespec *rem)
-{
- Assert(req);
-
- return _nanosleep(req, rem);
-}
-
-
-
/* Some dummy implementation for LibC functions */
extern "C" pid_t getpid(void)
diff --git a/repos/ports/src/virtualbox5/audio.cc b/repos/ports/src/virtualbox5/audio.cc
new file mode 100644
index 0000000000..f40f66217a
--- /dev/null
+++ b/repos/ports/src/virtualbox5/audio.cc
@@ -0,0 +1,538 @@
+/*
+ * \brief Genode audio driver backend
+ * \author Josef Soentgen
+ * \author Alexander Boettcher
+ * \date 2015-05-17
+ */
+
+/*
+ * Copyright (C) 2015-2017 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
+
+/* Genode includes */
+#include
+#include
+#include
+
+#include
+
+/* VBox Genode specific */
+#include "vmm.h"
+
+/* VBox includes */
+#include "AudioMixBuffer.h"
+#include "VBoxDD.h" /* for g_DrvHostOSSAudio */
+#include /* for PDMIBASE_2_PDMDRV */
+
+
+enum {
+ VBOX_CHANNELS = 2,
+ VBOX_SAMPLE_SIZE = sizeof(int16_t),
+
+ OUT_PACKET_NUM = 16, /* number of buffered packets */
+
+ OUT_SAMPLES = Audio_out::PERIOD,
+ IN_SAMPLES = Audio_in::PERIOD,
+};
+
+static char const * const channel_names[] = { "front left", "front right" };
+
+struct GenodeVoiceOut
+{
+ PDMAUDIOHSTSTRMOUT pStreamOut;
+ Genode::Constructible audio[VBOX_CHANNELS];
+ Audio_out::Packet *packet { nullptr };
+ uint32_t sample_pos { 0U };
+};
+
+struct GenodeVoiceIn
+{
+ PDMAUDIOHSTSTRMIN pStreamIn;
+ Genode::Constructible audio;
+ Audio_in::Packet *packet { nullptr };
+ uint32_t sample_pos { 0U };
+};
+
+typedef struct DRVHOSTOSSAUDIO
+{
+ PPDMDRVINS pDrvIns;
+ PDMIHOSTAUDIO IHostAudio;
+} DRVHOSTOSSAUDIO, *PDRVHOSTOSSAUDIO;
+
+static uint32_t read_samples(GenodeVoiceIn *in,
+ PPDMAUDIOMIXBUF const mixer_buf)
+{
+ Audio_in::Stream &stream = *in->audio->stream();
+ Audio_in::Packet *p = in->packet;
+
+ /* reset if packet became invalid */
+ if (p && !p->valid()) {
+ in->packet = p = nullptr;
+ in->sample_pos = 0;
+ }
+
+ uint32_t samples = RT_MIN(AudioMixBufFree(mixer_buf),
+ IN_SAMPLES - in->sample_pos);
+ uint32_t read_samples = 0;
+
+ while (samples) {
+ if (!p || !p->valid()) {
+ /* get new packet if current is invalid */
+ p = stream.get(stream.pos());
+ if (!p || !p->valid())
+ return read_samples;
+ }
+
+ /* convert samples */
+ uint32_t const bytes = AUDIOMIXBUF_S2B(mixer_buf, samples);
+ int16_t buf[bytes / sizeof(int16_t)];
+ for (unsigned i = 0; i < samples; i++) {
+ int16_t const v = p->content()[in->sample_pos + i] * 32767;
+ buf[(i * 2) + 0] = v;
+ buf[(i * 2) + 1] = v;
+ }
+
+ /* transfer samples to mixer */
+ uint32_t samples_written = 0;
+ int rc = AudioMixBufWriteCirc(mixer_buf, buf, sizeof(buf),
+ &samples_written);
+ if (RT_FAILURE(rc))
+ Genode::error("AudioMixBufWriteCirc failed rc=%d", rc);
+
+ Assert(samples >= samples_written);
+ read_samples += samples_written;
+
+ /* stop processing when mixer does not take all of our samples */
+ if (samples_written != samples) {
+ Assert (in->sample_pos + samples_written < IN_SAMPLES);
+
+ /* remember packet for later processing */
+ in->packet = p;
+ in->sample_pos += samples_written;
+
+ return read_samples;
+ }
+
+ /* reset an previously only partial processed packet */
+ if (p == in->packet) {
+ in->packet = nullptr;
+ in->sample_pos = 0;
+
+ samples = RT_MIN(AudioMixBufFree(mixer_buf),
+ IN_SAMPLES - in->sample_pos);
+ } else
+ samples -= samples_written;
+
+ /* current packet is completely processed */
+ p->invalidate();
+ p->mark_as_recorded();
+ stream.increment_position();
+
+ /* next packet */
+ p = stream.next(p);
+ }
+
+ return read_samples;
+}
+
+static uint32_t write_samples(GenodeVoiceOut *out,
+ PPDMAUDIOMIXBUF const mixer_buf)
+{
+ Audio_out::Connection * const c = &*out->audio[0];
+
+ /* samples in byte available for sending out */
+ uint32_t samples = RT_MIN(AudioMixBufAvail(mixer_buf),
+ OUT_SAMPLES - out->sample_pos);
+ uint32_t written_samples = 0;
+
+ while (samples)
+ {
+ if (c->stream()->queued() > OUT_PACKET_NUM)
+ return written_samples;
+
+ if (out->packet == nullptr) {
+
+ try {
+ out->packet = c->stream()->alloc();
+ } catch (Audio_out::Stream::Alloc_failed) {
+ LogWarn(("stream alloc failed\n"));
+ return written_samples;
+ }
+ }
+
+ /* assign the channels to audio streams */
+ Audio_out::Packet *p[VBOX_CHANNELS] = { out->packet, nullptr };
+ uint32_t const ppos = out->audio[0]->stream()->packet_position(p[0]);
+ p[1] = out->audio[1]->stream()->get(ppos);
+
+ static_assert(VBOX_CHANNELS == 2, "Channel count does not match");
+
+ /* copy */
+ float * const left = p[0]->content();
+ float * const right = p[1]->content();
+
+ /* setup convert buffer */
+ uint32_t const bytes = AUDIOMIXBUF_S2B(mixer_buf, samples);
+ int16_t buf[bytes / sizeof(int16_t)];
+
+ /* read mixer data in */
+ uint32_t samples_processed = 0;
+ int rc = AudioMixBufReadCirc(mixer_buf, buf, bytes, &samples_processed);
+
+ Assert(samples >= samples_processed);
+ written_samples += samples_processed;
+
+ if (RT_FAILURE(rc))
+ LogWarn(("AudioMixBufReadCirc failed rc=%Rrc\n", rc));
+
+ for (unsigned i = 0; i < samples_processed; i++, out->sample_pos++) {
+ left [out->sample_pos] = (float)(buf[i * VBOX_CHANNELS + 0])
+ / 32768.0f;
+ right[out->sample_pos] = (float)(buf[i * VBOX_CHANNELS + 1])
+ / 32768.0f;
+ }
+
+ Assert(out->sample_pos <= OUT_SAMPLES);
+
+ /* submit package if enough samples are in */
+ if (out->sample_pos == OUT_SAMPLES) {
+ /* submit */
+ for (unsigned i = 0; i < VBOX_CHANNELS; i++)
+ out->audio[i]->submit(p[i]);
+
+ /* reset packet information */
+ out->sample_pos = 0;
+ out->packet = nullptr;
+ }
+
+ /* check for additional samples */
+ samples = RT_MIN(AudioMixBufAvail(mixer_buf),
+ OUT_SAMPLES - out->sample_pos);
+ }
+
+ return written_samples;
+}
+
+
+static DECLCALLBACK(int) drvHostOSSAudioControlIn(PPDMIHOSTAUDIO,
+ PPDMAUDIOHSTSTRMIN data,
+ PDMAUDIOSTREAMCMD cmd)
+{
+ LogFlowFuncEnter();
+
+ AssertPtrReturn(data, VERR_INVALID_POINTER);
+ GenodeVoiceIn * const in = reinterpret_cast(data);
+
+ switch (cmd) {
+ case PDMAUDIOSTREAMCMD_ENABLE:
+ in->audio->start();
+ return VINF_SUCCESS;
+ case PDMAUDIOSTREAMCMD_DISABLE:
+ in->audio->stop();
+ return VINF_SUCCESS;
+ case PDMAUDIOSTREAMCMD_RESUME:
+ case PDMAUDIOSTREAMCMD_PAUSE:
+ default:
+ AssertMsgFailed(("Invalid command %ld\n", cmd));
+ return VERR_INVALID_PARAMETER;
+ }
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioControlOut(PPDMIHOSTAUDIO,
+ PPDMAUDIOHSTSTRMOUT data,
+ PDMAUDIOSTREAMCMD cmd)
+{
+ LogFlowFuncEnter();
+
+ AssertPtrReturn(data, VERR_INVALID_POINTER);
+
+ GenodeVoiceOut * const out = reinterpret_cast(data);
+
+ switch (cmd) {
+ case PDMAUDIOSTREAMCMD_ENABLE:
+ for (unsigned i = 0; i < VBOX_CHANNELS; i++)
+ out->audio[i]->start();
+ return VINF_SUCCESS;
+
+ case PDMAUDIOSTREAMCMD_DISABLE:
+ /* fill up unfinished packets with empty samples and push to stream */
+ if (out->packet) {
+ Audio_out::Packet *p[VBOX_CHANNELS] = { out->packet, nullptr };
+ uint32_t const ppos = out->audio[0]->stream()->packet_position(out->packet);
+ p[1] = out->audio[1]->stream()->get(ppos);
+
+ float * const left = p[0]->content();
+ float * const right = p[1]->content();
+
+ memset(left , 0, (OUT_SAMPLES - out->sample_pos)
+ * Audio_out::SAMPLE_SIZE);
+ memset(right, 0, (OUT_SAMPLES - out->sample_pos)
+ * Audio_out::SAMPLE_SIZE);
+
+ for (unsigned i = 0; i < VBOX_CHANNELS; i++)
+ out->audio[i]->submit(p[i]);
+
+ /* reset packet information */
+ out->sample_pos = 0;
+ out->packet = nullptr;
+ }
+
+ /* stop further processing */
+ for (unsigned i = 0; i < VBOX_CHANNELS; i++) {
+ out->audio[i]->stop();
+ out->audio[i]->stream()->invalidate_all();
+ }
+ return VINF_SUCCESS;
+
+ case PDMAUDIOSTREAMCMD_RESUME:
+ case PDMAUDIOSTREAMCMD_PAUSE:
+ default:
+ AssertMsgFailed(("Invalid command %ld\n", cmd));
+ return VERR_INVALID_PARAMETER;
+ }
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioInit(PPDMIHOSTAUDIO)
+{
+ LogFlowFuncEnter();
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioCaptureIn(PPDMIHOSTAUDIO,
+ PPDMAUDIOHSTSTRMIN data,
+ uint32_t * const samples)
+{
+ AssertPtrReturn(data, VERR_INVALID_POINTER);
+ GenodeVoiceIn * const in = reinterpret_cast(data);
+
+ uint32_t const total_samples = read_samples(in, &data->MixBuf);
+
+ if (total_samples) {
+ int rc = AudioMixBufMixToParent(&data->MixBuf, total_samples, nullptr);
+ if (RT_FAILURE(rc))
+ LogWarn(("AudioMixBufMixToParent failed rc=%Rrc\n", rc));
+ }
+
+ if (samples)
+ *samples = total_samples;
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioFiniIn(PPDMIHOSTAUDIO,
+ PPDMAUDIOHSTSTRMIN data)
+{
+ LogFlowFuncEnter();
+ AssertPtrReturn(data, VERR_INVALID_POINTER);
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioFiniOut(PPDMIHOSTAUDIO,
+ PPDMAUDIOHSTSTRMOUT data)
+{
+ LogFlowFuncEnter();
+ AssertPtrReturn(data, VERR_INVALID_POINTER);
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioGetConf(PPDMIHOSTAUDIO,
+ PPDMAUDIOBACKENDCFG cfg)
+{
+ cfg->cbStreamOut = sizeof(GenodeVoiceOut);
+ cfg->cbStreamIn = sizeof(GenodeVoiceIn);
+ cfg->cMaxHstStrmsOut = 1;
+ cfg->cMaxHstStrmsIn = 1;
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioInitIn(PPDMIHOSTAUDIO,
+ PPDMAUDIOHSTSTRMIN const data,
+ PPDMAUDIOSTREAMCFG const cfg,
+ PPDMAUDIOSTREAMCFG,
+ PDMAUDIORECSOURCE,
+ uint32_t *samples)
+{
+ LogFlowFuncEnter();
+
+ AssertPtrReturn(data, VERR_INVALID_POINTER);
+ AssertPtrReturn(cfg, VERR_INVALID_POINTER);
+
+ GenodeVoiceIn * in = reinterpret_cast(data);
+
+ try {
+ in->audio.construct(genode_env(), "left");
+ } catch (...) {
+ Genode::error("could not establish Audio_in connection");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ if (samples)
+ *samples = IN_SAMPLES;
+
+ Genode::log("--- using Audio_in session ---");
+ Genode::log("freq: ", cfg->uHz);
+ Genode::log("channels: ", cfg->cChannels);
+ Genode::log("format: ", (int)cfg->enmFormat);
+
+ LogFlowFuncLeave();
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioInitOut(PPDMIHOSTAUDIO,
+ PPDMAUDIOHSTSTRMOUT const data,
+ PPDMAUDIOSTREAMCFG const cfg,
+ PPDMAUDIOSTREAMCFG,
+ uint32_t *samples)
+{
+ LogFlowFuncEnter();
+
+ AssertPtrReturn(data, VERR_INVALID_POINTER);
+ AssertPtrReturn(cfg, VERR_INVALID_POINTER);
+
+ GenodeVoiceOut * out = reinterpret_cast(data);
+
+ if (cfg->cChannels != VBOX_CHANNELS) {
+ Genode::error("only ", (int)VBOX_CHANNELS, " channels supported ",
+ "( ", cfg->cChannels, " were requested)");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ if (cfg->uHz != Audio_out::SAMPLE_RATE) {
+ Genode::error("only ", (int)Audio_out::SAMPLE_RATE,
+ " frequency supported (", cfg->uHz, " was requested)");
+ return VERR_GENERAL_FAILURE;
+ }
+
+ for (int i = 0; i < VBOX_CHANNELS; i++) {
+ try {
+ out->audio[i].construct(genode_env(), channel_names[i]);
+ } catch (...) {
+ Genode::error("could not establish Audio_out connection");
+ while (i > 0) {
+ out->audio[--i].destruct();
+ }
+ return VERR_GENERAL_FAILURE;
+ }
+ }
+
+ if (samples)
+ *samples = OUT_SAMPLES;
+
+ Genode::log("--- using Audio_out session ---");
+ Genode::log("freq: ", cfg->uHz);
+ Genode::log("channels: ", cfg->cChannels);
+ Genode::log("format: ", (int)cfg->enmFormat);
+
+ LogFlowFuncLeave();
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(bool) drvHostOSSAudioIsEnabled(PPDMIHOSTAUDIO, PDMAUDIODIR)
+{
+ return true;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioPlayOut(PPDMIHOSTAUDIO,
+ PPDMAUDIOHSTSTRMOUT const data,
+ uint32_t *samples)
+{
+ AssertPtrReturn(data, VERR_INVALID_POINTER);
+ GenodeVoiceOut * const out = reinterpret_cast(data);
+
+ uint32_t const total_samples = write_samples(out, &data->MixBuf);
+ if (total_samples)
+ AudioMixBufFinish(&data->MixBuf, total_samples);
+
+ if (samples)
+ *samples = total_samples;
+
+ return VINF_SUCCESS;
+}
+
+static DECLCALLBACK(void) drvHostOSSAudioShutdown(PPDMIHOSTAUDIO)
+{
+ LogFlowFuncEnter();
+}
+
+static DECLCALLBACK(void *) drvHostOSSAudioQueryInterface(PPDMIBASE pInterface,
+ const char *pszIID)
+{
+ LogFlowFuncEnter();
+
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVHOSTOSSAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTOSSAUDIO);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
+
+ return NULL;
+}
+
+static DECLCALLBACK(int) drvHostOSSAudioConstruct(PPDMDRVINS pDrvIns,
+ PCFGMNODE, uint32_t)
+{
+ PDRVHOSTOSSAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTOSSAUDIO);
+ LogFlowFuncEnter();
+
+ pThis->pDrvIns = pDrvIns;
+ pDrvIns->IBase.pfnQueryInterface = drvHostOSSAudioQueryInterface;
+ PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostOSSAudio);
+
+ return VINF_SUCCESS;
+}
+
+
+const PDMDRVREG g_DrvHostOSSAudio =
+{
+ /* u32Version */
+ PDM_DRVREG_VERSION,
+ /* szName */
+ "OSSAudio",
+ /* szRCMod */
+ "",
+ /* szR0Mod */
+ "",
+ /* pszDescription */
+ "OSS audio host driver",
+ /* fFlags */
+ PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+ /* fClass. */
+ PDM_DRVREG_CLASS_AUDIO,
+ /* cMaxInstances */
+ ~0U,
+ /* cbInstance */
+ sizeof(DRVHOSTOSSAUDIO),
+ /* pfnConstruct */
+ drvHostOSSAudioConstruct,
+ /* pfnDestruct */
+ NULL,
+ /* pfnRelocate */
+ NULL,
+ /* pfnIOCtl */
+ NULL,
+ /* pfnPowerOn */
+ NULL,
+ /* pfnReset */
+ NULL,
+ /* pfnSuspend */
+ NULL,
+ /* pfnResume */
+ NULL,
+ /* pfnAttach */
+ NULL,
+ /* pfnDetach */
+ NULL,
+ /* pfnPowerOff */
+ NULL,
+ /* pfnSoftReset */
+ NULL,
+ /* u32EndVersion */
+ PDM_DRVREG_VERSION
+};
diff --git a/repos/ports/src/virtualbox5/drivers.cc b/repos/ports/src/virtualbox5/drivers.cc
index 610ba02b29..768dc51021 100644
--- a/repos/ports/src/virtualbox5/drivers.cc
+++ b/repos/ports/src/virtualbox5/drivers.cc
@@ -20,17 +20,15 @@ extern "C" int VBoxDriversRegister(PCPDMDRVREGCB pCallbacks, uint32_t u32Version
PDMDRVREG const *drvs[] = {
&g_DrvKeyboardQueue,
&g_DrvMouseQueue,
-// &g_DrvBlock,
-// &g_DrvMediaISO,
&g_DrvACPI,
&g_DrvChar,
-// &g_DrvRawImage,
&g_DrvRawFile,
&g_DrvHostSerial,
&g_DrvVD,
&g_DrvHostInterface,
&g_DrvVUSBRootHub,
&g_DrvAUDIO,
+ &g_DrvHostOSSAudio,
&g_DrvHostNullAudio,
0
};