From d729b8b9e447cea764e06073af73d3b47c66af2d Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Thu, 12 Jan 2017 07:02:01 +0100 Subject: [PATCH] Implement audio support Audio playback still has a delay about 1-2 seconds but it's usable. This also moves the platform policy class into its own namespace to be not specific to just window management. --- Android.mk | 23 +- android/CMakeLists.txt | 7 + android/audio/Android.mk | 31 - android/audio/audio_hw.c | 694 ------------------ android/audio/audio_hw.cpp | 676 +++++++++++++++++ src/CMakeLists.txt | 11 +- src/anbox/audio/client_info.h | 36 + src/anbox/audio/server.cpp | 109 +++ src/anbox/audio/server.h | 56 ++ src/anbox/audio/sink.h | 35 + src/anbox/audio/source.h | 36 + src/anbox/cmds/run.cpp | 4 + src/anbox/graphics/buffer_queue.cpp | 11 + src/anbox/graphics/buffer_queue.h | 2 + src/anbox/graphics/buffered_io_stream.cpp | 2 +- .../network/published_socket_connector.h | 3 +- .../default_policy.cpp} | 20 +- .../default_policy.h} | 16 +- .../policy.cpp} | 6 +- .../platform_policy.h => platform/policy.h} | 19 +- src/anbox/ubuntu/audio_sink.cpp | 117 +++ src/anbox/ubuntu/audio_sink.h | 54 ++ src/anbox/ubuntu/platform_policy.cpp | 12 +- src/anbox/ubuntu/platform_policy.h | 7 +- src/anbox/wm/manager.cpp | 8 +- src/anbox/wm/manager.h | 8 +- tests/anbox/graphics/layer_composer_tests.cpp | 10 +- 27 files changed, 1243 insertions(+), 770 deletions(-) delete mode 100644 android/audio/Android.mk delete mode 100644 android/audio/audio_hw.c create mode 100644 android/audio/audio_hw.cpp create mode 100644 src/anbox/audio/client_info.h create mode 100644 src/anbox/audio/server.cpp create mode 100644 src/anbox/audio/server.h create mode 100644 src/anbox/audio/sink.h create mode 100644 src/anbox/audio/source.h rename src/anbox/{wm/default_platform_policy.cpp => platform/default_policy.cpp} (74%) rename src/anbox/{wm/default_platform_policy.h => platform/default_policy.h} (69%) rename src/anbox/{wm/platform_policy.cpp => platform/policy.cpp} (89%) rename src/anbox/{wm/platform_policy.h => platform/policy.h} (70%) create mode 100644 src/anbox/ubuntu/audio_sink.cpp create mode 100644 src/anbox/ubuntu/audio_sink.h diff --git a/Android.mk b/Android.mk index 5819a7b7..780f4495 100644 --- a/Android.mk +++ b/Android.mk @@ -73,13 +73,27 @@ LOCAL_SRC_FILES := \ LOCAL_MODULE := hwcomposer.anbox LOCAL_CFLAGS:= -DLOG_TAG=\"hwcomposer\" LOCAL_C_INCLUDES += \ - $(LOCAL_PATH)/../device/generic/goldfish/opengl/host/include/libOpenglRender \ - $(LOCAL_PATH)/../device/generic/goldfish/opengl/shared/OpenglCodecCommon \ - $(LOCAL_PATH)/../device/generic/goldfish/opengl/system/renderControl_enc \ - $(LOCAL_PATH)/../device/generic/goldfish/opengl/system/OpenglSystemCommon + $(LOCAL_PATH)/android/opengl/host/include/libOpenglRender \ + $(LOCAL_PATH)/android/opengl/shared/OpenglCodecCommon \ + $(LOCAL_PATH)/android/opengl/system/renderControl_enc \ + $(LOCAL_PATH)/android/opengl/system/OpenglSystemCommon LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY) +include $(CLEAR_VARS) +LOCAL_MODULE := audio.primary.goldfish +LOCAL_MODULE_RELATIVE_PATH := hw +LOCAL_MODULE_TAGS := optional +LOCAL_SHARED_LIBRARIES := libcutils liblog +LOCAL_SRC_FILES := \ + android/audio/audio_hw.cpp +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/src +LOCAL_SHARED_LIBRARIES += libdl +LOCAL_CFLAGS := -Wno-unused-parameter + +include $(BUILD_SHARED_LIBRARY) + # Include the Android.mk files below will override LOCAL_PATH so we # have to take a copy of it here. TMP_PATH := $(LOCAL_PATH) @@ -89,7 +103,6 @@ include $(TMP_PATH)/android/fingerprint/Android.mk include $(TMP_PATH)/android/power/Android.mk include $(TMP_PATH)/android/qemu-props/Android.mk include $(TMP_PATH)/android/qemud/Android.mk -include $(TMP_PATH)/android/audio/Android.mk include $(TMP_PATH)/android/sensors/Android.mk include $(TMP_PATH)/android/opengl/Android.mk include $(TMP_PATH)/android/gps/Android.mk diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt index 7d818eaa..58b3614d 100644 --- a/android/CMakeLists.txt +++ b/android/CMakeLists.txt @@ -29,6 +29,10 @@ set(HWCOMPOSER_SOURCES add_library(hwcomposer.anbox SHARED ${HWCOMPOSER_SOURCES}) +set(AUDIO_SOURCES + audio/audio_hw.cpp) +add_library(audio.goldfish SHARED ${AUDIO_SOURCES}) + # As we're adding Android specific bits in this project we can't # build this safely within default build anymore. We keep this # for easy integration into used IDEs. @@ -38,3 +42,6 @@ set_target_properties(anboxd set_target_properties(hwcomposer.anbox PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1) +set_target_properties(audio.goldfish + PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1) + diff --git a/android/audio/Android.mk b/android/audio/Android.mk deleted file mode 100644 index d9d2f131..00000000 --- a/android/audio/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (C) 2011 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. - -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := audio.primary.goldfish -LOCAL_MODULE_RELATIVE_PATH := hw -LOCAL_MODULE_TAGS := optional - -LOCAL_SHARED_LIBRARIES := libcutils liblog - -LOCAL_SRC_FILES := audio_hw.c - -LOCAL_SHARED_LIBRARIES += libdl -LOCAL_CFLAGS := -Wno-unused-parameter - -include $(BUILD_SHARED_LIBRARY) diff --git a/android/audio/audio_hw.c b/android/audio/audio_hw.c deleted file mode 100644 index cab9aadc..00000000 --- a/android/audio/audio_hw.c +++ /dev/null @@ -1,694 +0,0 @@ -/* - * Copyright (C) 2012 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 LOG_TAG "audio_hw_generic" -/*#define LOG_NDEBUG 0*/ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - - -#define AUDIO_DEVICE_NAME "/dev/eac" -#define OUT_SAMPLING_RATE 44100 -#define OUT_BUFFER_SIZE 4096 -#define OUT_LATENCY_MS 20 -#define IN_SAMPLING_RATE 8000 -#define IN_BUFFER_SIZE 320 - - -struct generic_audio_device { - struct audio_hw_device device; - pthread_mutex_t lock; - struct audio_stream_out *output; - struct audio_stream_in *input; - int fd; - bool mic_mute; -}; - - -struct generic_stream_out { - struct audio_stream_out stream; - struct generic_audio_device *dev; - audio_devices_t device; -}; - -struct generic_stream_in { - struct audio_stream_in stream; - struct generic_audio_device *dev; - audio_devices_t device; -}; - - -static uint32_t out_get_sample_rate(const struct audio_stream *stream) -{ - return OUT_SAMPLING_RATE; -} - -static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) -{ - return -ENOSYS; -} - -static size_t out_get_buffer_size(const struct audio_stream *stream) -{ - return OUT_BUFFER_SIZE; -} - -static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) -{ - return AUDIO_CHANNEL_OUT_STEREO; -} - -static audio_format_t out_get_format(const struct audio_stream *stream) -{ - return AUDIO_FORMAT_PCM_16_BIT; -} - -static int out_set_format(struct audio_stream *stream, audio_format_t format) -{ - return -ENOSYS; -} - -static int out_standby(struct audio_stream *stream) -{ - // out_standby is a no op - return 0; -} - -static int out_dump(const struct audio_stream *stream, int fd) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - - dprintf(fd, "\tout_dump:\n" - "\t\tsample rate: %u\n" - "\t\tbuffer size: %u\n" - "\t\tchannel mask: %08x\n" - "\t\tformat: %d\n" - "\t\tdevice: %08x\n" - "\t\taudio dev: %p\n\n", - out_get_sample_rate(stream), - out_get_buffer_size(stream), - out_get_channels(stream), - out_get_format(stream), - out->device, - out->dev); - - return 0; -} - -static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - struct str_parms *parms; - char value[32]; - int ret; - long val; - char *end; - - parms = str_parms_create_str(kvpairs); - - ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, - value, sizeof(value)); - if (ret >= 0) { - errno = 0; - val = strtol(value, &end, 10); - if (errno == 0 && (end != NULL) && (*end == '\0') && ((int)val == val)) { - out->device = (int)val; - } else { - ret = -EINVAL; - } - } - - str_parms_destroy(parms); - return ret; -} - -static char * out_get_parameters(const struct audio_stream *stream, const char *keys) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - struct str_parms *query = str_parms_create_str(keys); - char *str; - char value[256]; - struct str_parms *reply = str_parms_create(); - int ret; - - ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); - if (ret >= 0) { - str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, out->device); - str = strdup(str_parms_to_str(reply)); - } else { - str = strdup(keys); - } - - str_parms_destroy(query); - str_parms_destroy(reply); - return str; -} - -static uint32_t out_get_latency(const struct audio_stream_out *stream) -{ - return OUT_LATENCY_MS; -} - -static int out_set_volume(struct audio_stream_out *stream, float left, - float right) -{ - return -ENOSYS; -} - -static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, - size_t bytes) -{ - struct generic_stream_out *out = (struct generic_stream_out *)stream; - struct generic_audio_device *adev = out->dev; - - pthread_mutex_lock(&adev->lock); - if (adev->fd >= 0) - bytes = write(adev->fd, buffer, bytes); - pthread_mutex_unlock(&adev->lock); - - return bytes; -} - -static int out_get_render_position(const struct audio_stream_out *stream, - uint32_t *dsp_frames) -{ - return -ENOSYS; -} - -static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - // out_add_audio_effect is a no op - return 0; -} - -static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - // out_remove_audio_effect is a no op - return 0; -} - -static int out_get_next_write_timestamp(const struct audio_stream_out *stream, - int64_t *timestamp) -{ - return -ENOSYS; -} - -/** audio_stream_in implementation **/ -static uint32_t in_get_sample_rate(const struct audio_stream *stream) -{ - return IN_SAMPLING_RATE; -} - -static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) -{ - return -ENOSYS; -} - -static size_t in_get_buffer_size(const struct audio_stream *stream) -{ - return IN_BUFFER_SIZE; -} - -static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) -{ - return AUDIO_CHANNEL_IN_MONO; -} - -static audio_format_t in_get_format(const struct audio_stream *stream) -{ - return AUDIO_FORMAT_PCM_16_BIT; -} - -static int in_set_format(struct audio_stream *stream, audio_format_t format) -{ - return -ENOSYS; -} - -static int in_standby(struct audio_stream *stream) -{ - // in_standby is a no op - return 0; -} - -static int in_dump(const struct audio_stream *stream, int fd) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - - dprintf(fd, "\tin_dump:\n" - "\t\tsample rate: %u\n" - "\t\tbuffer size: %u\n" - "\t\tchannel mask: %08x\n" - "\t\tformat: %d\n" - "\t\tdevice: %08x\n" - "\t\taudio dev: %p\n\n", - in_get_sample_rate(stream), - in_get_buffer_size(stream), - in_get_channels(stream), - in_get_format(stream), - in->device, - in->dev); - - return 0; -} - -static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - struct str_parms *parms; - char value[32]; - int ret; - long val; - char *end; - - parms = str_parms_create_str(kvpairs); - - ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, - value, sizeof(value)); - if (ret >= 0) { - errno = 0; - val = strtol(value, &end, 10); - if ((errno == 0) && (end != NULL) && (*end == '\0') && ((int)val == val)) { - in->device = (int)val; - } else { - ret = -EINVAL; - } - } - - str_parms_destroy(parms); - return ret; -} - -static char * in_get_parameters(const struct audio_stream *stream, - const char *keys) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - struct str_parms *query = str_parms_create_str(keys); - char *str; - char value[256]; - struct str_parms *reply = str_parms_create(); - int ret; - - ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); - if (ret >= 0) { - str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, in->device); - str = strdup(str_parms_to_str(reply)); - } else { - str = strdup(keys); - } - - str_parms_destroy(query); - str_parms_destroy(reply); - return str; -} - -static int in_set_gain(struct audio_stream_in *stream, float gain) -{ - // in_set_gain is a no op - return 0; -} - -static ssize_t in_read(struct audio_stream_in *stream, void* buffer, - size_t bytes) -{ - struct generic_stream_in *in = (struct generic_stream_in *)stream; - struct generic_audio_device *adev = in->dev; - - pthread_mutex_lock(&adev->lock); - if (adev->fd >= 0) - bytes = read(adev->fd, buffer, bytes); - if (adev->mic_mute && (bytes > 0)) { - memset(buffer, 0, bytes); - } - pthread_mutex_unlock(&adev->lock); - - return bytes; -} - -static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) -{ - return 0; -} - -static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - // in_add_audio_effect is a no op - return 0; -} - -static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) -{ - // in_add_audio_effect is a no op - return 0; -} - -static int adev_open_output_stream(struct audio_hw_device *dev, - audio_io_handle_t handle, - audio_devices_t devices, - audio_output_flags_t flags, - struct audio_config *config, - struct audio_stream_out **stream_out, - const char *address __unused) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - struct generic_stream_out *out; - int ret = 0; - - pthread_mutex_lock(&adev->lock); - if (adev->output != NULL) { - ret = -ENOSYS; - goto error; - } - - if ((config->format != AUDIO_FORMAT_PCM_16_BIT) || - (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) || - (config->sample_rate != OUT_SAMPLING_RATE)) { - ALOGE("Error opening output stream format %d, channel_mask %04x, sample_rate %u", - config->format, config->channel_mask, config->sample_rate); - config->format = AUDIO_FORMAT_PCM_16_BIT; - config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; - config->sample_rate = OUT_SAMPLING_RATE; - ret = -EINVAL; - goto error; - } - - out = (struct generic_stream_out *)calloc(1, sizeof(struct generic_stream_out)); - - out->stream.common.get_sample_rate = out_get_sample_rate; - out->stream.common.set_sample_rate = out_set_sample_rate; - out->stream.common.get_buffer_size = out_get_buffer_size; - out->stream.common.get_channels = out_get_channels; - out->stream.common.get_format = out_get_format; - out->stream.common.set_format = out_set_format; - out->stream.common.standby = out_standby; - out->stream.common.dump = out_dump; - out->stream.common.set_parameters = out_set_parameters; - out->stream.common.get_parameters = out_get_parameters; - out->stream.common.add_audio_effect = out_add_audio_effect; - out->stream.common.remove_audio_effect = out_remove_audio_effect; - out->stream.get_latency = out_get_latency; - out->stream.set_volume = out_set_volume; - out->stream.write = out_write; - out->stream.get_render_position = out_get_render_position; - out->stream.get_next_write_timestamp = out_get_next_write_timestamp; - - out->dev = adev; - out->device = devices; - adev->output = (struct audio_stream_out *)out; - *stream_out = &out->stream; - -error: - pthread_mutex_unlock(&adev->lock); - - return ret; -} - -static void adev_close_output_stream(struct audio_hw_device *dev, - struct audio_stream_out *stream) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - pthread_mutex_lock(&adev->lock); - if (stream == adev->output) { - free(stream); - adev->output = NULL; - } - pthread_mutex_unlock(&adev->lock); -} - -static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) -{ - return 0; -} - -static char * adev_get_parameters(const struct audio_hw_device *dev, - const char *keys) -{ - return strdup(""); -} - -static int adev_init_check(const struct audio_hw_device *dev) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - if (adev->fd >= 0) - return 0; - - return -ENODEV; -} - -static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) -{ - // adev_set_voice_volume is a no op (simulates phones) - return 0; -} - -static int adev_set_master_volume(struct audio_hw_device *dev, float volume) -{ - return -ENOSYS; -} - -static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) -{ - return -ENOSYS; -} - -static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) -{ - return -ENOSYS; -} - -static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) -{ - return -ENOSYS; -} - -static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) -{ - // adev_set_mode is a no op (simulates phones) - return 0; -} - -static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - pthread_mutex_lock(&adev->lock); - adev->mic_mute = state; - pthread_mutex_unlock(&adev->lock); - return 0; -} - -static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - pthread_mutex_lock(&adev->lock); - *state = adev->mic_mute; - pthread_mutex_unlock(&adev->lock); - - return 0; -} - -static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, - const struct audio_config *config) -{ - return IN_BUFFER_SIZE; -} - -static int adev_open_input_stream(struct audio_hw_device *dev, - audio_io_handle_t handle, - audio_devices_t devices, - struct audio_config *config, - struct audio_stream_in **stream_in, - audio_input_flags_t flags __unused, - const char *address __unused, - audio_source_t source __unused) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - struct generic_stream_in *in; - int ret = 0; - - pthread_mutex_lock(&adev->lock); - if (adev->input != NULL) { - ret = -ENOSYS; - goto error; - } - - if ((config->format != AUDIO_FORMAT_PCM_16_BIT) || - (config->channel_mask != AUDIO_CHANNEL_IN_MONO) || - (config->sample_rate != IN_SAMPLING_RATE)) { - ALOGE("Error opening input stream format %d, channel_mask %04x, sample_rate %u", - config->format, config->channel_mask, config->sample_rate); - config->format = AUDIO_FORMAT_PCM_16_BIT; - config->channel_mask = AUDIO_CHANNEL_IN_MONO; - config->sample_rate = IN_SAMPLING_RATE; - ret = -EINVAL; - goto error; - } - - in = (struct generic_stream_in *)calloc(1, sizeof(struct generic_stream_in)); - - in->stream.common.get_sample_rate = in_get_sample_rate; - in->stream.common.set_sample_rate = in_set_sample_rate; - in->stream.common.get_buffer_size = in_get_buffer_size; - in->stream.common.get_channels = in_get_channels; - in->stream.common.get_format = in_get_format; - in->stream.common.set_format = in_set_format; - in->stream.common.standby = in_standby; - in->stream.common.dump = in_dump; - in->stream.common.set_parameters = in_set_parameters; - in->stream.common.get_parameters = in_get_parameters; - in->stream.common.add_audio_effect = in_add_audio_effect; - in->stream.common.remove_audio_effect = in_remove_audio_effect; - in->stream.set_gain = in_set_gain; - in->stream.read = in_read; - in->stream.get_input_frames_lost = in_get_input_frames_lost; - - in->dev = adev; - in->device = devices; - adev->input = (struct audio_stream_in *)in; - *stream_in = &in->stream; - -error: - pthread_mutex_unlock(&adev->lock); - - return ret; -} - -static void adev_close_input_stream(struct audio_hw_device *dev, - struct audio_stream_in *stream) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - pthread_mutex_lock(&adev->lock); - if (stream == adev->input) { - free(stream); - adev->input = NULL; - } - pthread_mutex_unlock(&adev->lock); -} - -static int adev_dump(const audio_hw_device_t *dev, int fd) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - const size_t SIZE = 256; - char buffer[SIZE]; - - dprintf(fd, "\nadev_dump:\n" - "\tfd: %d\n" - "\tmic_mute: %s\n" - "\toutput: %p\n" - "\tinput: %p\n\n", - adev->fd, - adev->mic_mute ? "true": "false", - adev->output, - adev->input); - - if (adev->output != NULL) - out_dump((const struct audio_stream *)adev->output, fd); - if (adev->input != NULL) - in_dump((const struct audio_stream *)adev->input, fd); - - return 0; -} - -static int adev_close(hw_device_t *dev) -{ - struct generic_audio_device *adev = (struct generic_audio_device *)dev; - - adev_close_output_stream((struct audio_hw_device *)dev, adev->output); - adev_close_input_stream((struct audio_hw_device *)dev, adev->input); - - if (adev->fd >= 0) - close(adev->fd); - - free(dev); - return 0; -} - -static int adev_open(const hw_module_t* module, const char* name, - hw_device_t** device) -{ - struct generic_audio_device *adev; - int fd; - - if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) - return -EINVAL; - - fd = open(AUDIO_DEVICE_NAME, O_RDWR); - if (fd < 0) - return -ENOSYS; - - adev = calloc(1, sizeof(struct generic_audio_device)); - - adev->fd = fd; - - adev->device.common.tag = HARDWARE_DEVICE_TAG; - adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; - adev->device.common.module = (struct hw_module_t *) module; - adev->device.common.close = adev_close; - - adev->device.init_check = adev_init_check; - adev->device.set_voice_volume = adev_set_voice_volume; - adev->device.set_master_volume = adev_set_master_volume; - adev->device.get_master_volume = adev_get_master_volume; - adev->device.set_master_mute = adev_set_master_mute; - adev->device.get_master_mute = adev_get_master_mute; - adev->device.set_mode = adev_set_mode; - adev->device.set_mic_mute = adev_set_mic_mute; - adev->device.get_mic_mute = adev_get_mic_mute; - adev->device.set_parameters = adev_set_parameters; - adev->device.get_parameters = adev_get_parameters; - adev->device.get_input_buffer_size = adev_get_input_buffer_size; - adev->device.open_output_stream = adev_open_output_stream; - adev->device.close_output_stream = adev_close_output_stream; - adev->device.open_input_stream = adev_open_input_stream; - adev->device.close_input_stream = adev_close_input_stream; - adev->device.dump = adev_dump; - - *device = &adev->device.common; - - return 0; -} - -static struct hw_module_methods_t hal_module_methods = { - .open = adev_open, -}; - -struct audio_module HAL_MODULE_INFO_SYM = { - .common = { - .tag = HARDWARE_MODULE_TAG, - .module_api_version = AUDIO_MODULE_API_VERSION_0_1, - .hal_api_version = HARDWARE_HAL_API_VERSION, - .id = AUDIO_HARDWARE_MODULE_ID, - .name = "Generic audio HW HAL", - .author = "The Android Open Source Project", - .methods = &hal_module_methods, - }, -}; diff --git a/android/audio/audio_hw.cpp b/android/audio/audio_hw.cpp new file mode 100644 index 00000000..f44e7382 --- /dev/null +++ b/android/audio/audio_hw.cpp @@ -0,0 +1,676 @@ +/* + * Copyright (C) 2012 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 LOG_TAG "audio_hw_generic" +#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "anbox/audio/client_info.h" + +#define AUDIO_DEVICE_NAME "/dev/anbox_audio" +#define OUT_SAMPLING_RATE 44100 +#define OUT_BUFFER_SIZE 4096 +#define OUT_LATENCY_MS 20 +#define IN_SAMPLING_RATE 8000 +#define IN_BUFFER_SIZE 320 + +struct generic_audio_device { + struct audio_hw_device device; + pthread_mutex_t lock; + struct audio_stream_out *output; + struct audio_stream_in *input; + bool mic_mute; +}; + +struct generic_stream_out { + struct audio_stream_out stream; + struct generic_audio_device *dev; + audio_devices_t device; + int fd; +}; + +struct generic_stream_in { + struct audio_stream_in stream; + struct generic_audio_device *dev; + audio_devices_t device; + int fd; +}; + +static uint32_t out_get_sample_rate(const struct audio_stream *stream) { + return OUT_SAMPLING_RATE; +} + +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) { + return -ENOSYS; +} + +static size_t out_get_buffer_size(const struct audio_stream *stream) { + return OUT_BUFFER_SIZE; +} + +static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) { + return AUDIO_CHANNEL_OUT_STEREO; +} + +static audio_format_t out_get_format(const struct audio_stream *stream) { + return AUDIO_FORMAT_PCM_16_BIT; +} + +static int out_set_format(struct audio_stream *stream, audio_format_t format) { + return -ENOSYS; +} + +static int out_standby(struct audio_stream *stream) { + return 0; +} + +static int out_dump(const struct audio_stream *stream, int fd) { + struct generic_stream_out *out = (struct generic_stream_out *)stream; + + dprintf(fd, + "\tout_dump:\n" + "\t\tsample rate: %u\n" + "\t\tbuffer size: %u\n" + "\t\tchannel mask: %08x\n" + "\t\tformat: %d\n" + "\t\tdevice: %08x\n" + "\t\taudio dev: %p\n\n", + out_get_sample_rate(stream), + out_get_buffer_size(stream), + out_get_channels(stream), + out_get_format(stream), + out->device, + out->dev); + + return 0; +} + +static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) { + struct generic_stream_out *out = (struct generic_stream_out *)stream; + struct str_parms *parms; + char value[32]; + int ret; + long val; + char *end; + + parms = str_parms_create_str(kvpairs); + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, + value, sizeof(value)); + if (ret >= 0) { + errno = 0; + val = strtol(value, &end, 10); + if (errno == 0 && (end != NULL) && (*end == '\0') && ((int)val == val)) { + out->device = (int)val; + } else { + ret = -EINVAL; + } + } + + str_parms_destroy(parms); + return ret; +} + +static char *out_get_parameters(const struct audio_stream *stream, const char *keys) { + struct generic_stream_out *out = (struct generic_stream_out *)stream; + struct str_parms *query = str_parms_create_str(keys); + char *str; + char value[256]; + struct str_parms *reply = str_parms_create(); + int ret; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); + if (ret >= 0) { + str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, out->device); + str = strdup(str_parms_to_str(reply)); + } else { + str = strdup(keys); + } + + str_parms_destroy(query); + str_parms_destroy(reply); + return str; +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) { + return OUT_LATENCY_MS; +} + +static int out_set_volume(struct audio_stream_out *stream, float left, + float right) { + return -ENOSYS; +} + +static ssize_t out_write(struct audio_stream_out *stream, const void *buffer, + size_t bytes) { + struct generic_stream_out *out = (struct generic_stream_out *)stream; + struct generic_audio_device *adev = out->dev; + + pthread_mutex_lock(&adev->lock); + if (out->fd >= 0) + bytes = write(out->fd, buffer, bytes); + pthread_mutex_unlock(&adev->lock); + return bytes; +} + +static int out_get_render_position(const struct audio_stream_out *stream, + uint32_t *dsp_frames) { + return -ENOSYS; +} + +static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { + return 0; +} + +static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { + return 0; +} + +static int out_get_next_write_timestamp(const struct audio_stream_out *stream, + int64_t *timestamp) { + return -ENOSYS; +} + +static uint32_t in_get_sample_rate(const struct audio_stream *stream) { + return IN_SAMPLING_RATE; +} + +static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) { + return -ENOSYS; +} + +static size_t in_get_buffer_size(const struct audio_stream *stream) { + return IN_BUFFER_SIZE; +} + +static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) { + return AUDIO_CHANNEL_IN_MONO; +} + +static audio_format_t in_get_format(const struct audio_stream *stream) { + return AUDIO_FORMAT_PCM_16_BIT; +} + +static int in_set_format(struct audio_stream *stream, audio_format_t format) { + return -ENOSYS; +} + +static int in_standby(struct audio_stream *stream) { + return 0; +} + +static int in_dump(const struct audio_stream *stream, int fd) { + struct generic_stream_in *in = (struct generic_stream_in *)stream; + + dprintf(fd, + "\tin_dump:\n" + "\t\tsample rate: %u\n" + "\t\tbuffer size: %u\n" + "\t\tchannel mask: %08x\n" + "\t\tformat: %d\n" + "\t\tdevice: %08x\n" + "\t\taudio dev: %p\n\n", + in_get_sample_rate(stream), + in_get_buffer_size(stream), + in_get_channels(stream), + in_get_format(stream), + in->device, + in->dev); + + return 0; +} + +static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) { + struct generic_stream_in *in = (struct generic_stream_in *)stream; + struct str_parms *parms; + char value[32]; + int ret; + long val; + char *end; + + parms = str_parms_create_str(kvpairs); + + ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, + value, sizeof(value)); + if (ret >= 0) { + errno = 0; + val = strtol(value, &end, 10); + if ((errno == 0) && (end != NULL) && (*end == '\0') && ((int)val == val)) { + in->device = (int)val; + } else { + ret = -EINVAL; + } + } + + str_parms_destroy(parms); + return ret; +} + +static char *in_get_parameters(const struct audio_stream *stream, + const char *keys) { + struct generic_stream_in *in = (struct generic_stream_in *)stream; + struct str_parms *query = str_parms_create_str(keys); + char *str; + char value[256]; + struct str_parms *reply = str_parms_create(); + int ret; + + ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value)); + if (ret >= 0) { + str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, in->device); + str = strdup(str_parms_to_str(reply)); + } else { + str = strdup(keys); + } + + str_parms_destroy(query); + str_parms_destroy(reply); + return str; +} + +static int in_set_gain(struct audio_stream_in *stream, float gain) { + return 0; +} + +static ssize_t in_read(struct audio_stream_in *stream, void *buffer, + size_t bytes) { + struct generic_stream_in *in = (struct generic_stream_in *)stream; + struct generic_audio_device *adev = in->dev; + + pthread_mutex_lock(&adev->lock); + if (in->fd >= 0) + bytes = read(in->fd, buffer, bytes); + if (adev->mic_mute && (bytes > 0)) { + memset(buffer, 0, bytes); + } + pthread_mutex_unlock(&adev->lock); + + return bytes; +} + +static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) { + return 0; +} + +static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { + return 0; +} + +static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) { + return 0; +} + +static int connect_audio_server(const anbox::audio::ClientInfo::Type &type) { + int fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (fd < 0) + return -errno; + + struct sockaddr_un addr; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, AUDIO_DEVICE_NAME, sizeof(addr.sun_path)); + + if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + close(fd); + return -errno; + } + + // We will send out client type information to the server and the + // server will either deny the request by closing the connection + // or by sending us the approved client details back. + anbox::audio::ClientInfo client_info{type}; + if (::write(fd, &client_info, sizeof(client_info)) < 0) { + close(fd); + return -EIO; + } + + auto bytes_read = ::read(fd, &client_info, sizeof(client_info)); + if (bytes_read < 0) { + close(fd); + return -EIO; + } + + // FIXME once we have real client details we need to check if we + // got everything we need or if anything is missing. + + ALOGE("Successfully connected Anbox audio server"); + + return fd; +} + +static int adev_open_output_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config, + struct audio_stream_out **stream_out, + const char *address __unused) { + struct generic_audio_device *adev = (struct generic_audio_device *)dev; + struct generic_stream_out *out; + int ret = 0, fd = 0; + + pthread_mutex_lock(&adev->lock); + if (adev->output != NULL) { + ret = -ENOSYS; + goto error; + } + + fd = connect_audio_server(anbox::audio::ClientInfo::Type::Playback); + if (fd < 0) { + ret = fd; + ALOGE("Failed to connect with Anbox audio servers (err %d)", ret); + goto error; + } + + if ((config->format != AUDIO_FORMAT_PCM_16_BIT) || + (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) || + (config->sample_rate != OUT_SAMPLING_RATE)) { + ALOGE("Error opening output stream format %d, channel_mask %04x, sample_rate %u", + config->format, config->channel_mask, config->sample_rate); + config->format = AUDIO_FORMAT_PCM_16_BIT; + config->channel_mask = AUDIO_CHANNEL_OUT_STEREO; + config->sample_rate = OUT_SAMPLING_RATE; + ret = -EINVAL; + goto error; + } + + out = (struct generic_stream_out *)calloc(1, sizeof(struct generic_stream_out)); + out->fd = fd; + + out->stream.common.get_sample_rate = out_get_sample_rate; + out->stream.common.set_sample_rate = out_set_sample_rate; + out->stream.common.get_buffer_size = out_get_buffer_size; + out->stream.common.get_channels = out_get_channels; + out->stream.common.get_format = out_get_format; + out->stream.common.set_format = out_set_format; + out->stream.common.standby = out_standby; + out->stream.common.dump = out_dump; + out->stream.common.set_parameters = out_set_parameters; + out->stream.common.get_parameters = out_get_parameters; + out->stream.common.add_audio_effect = out_add_audio_effect; + out->stream.common.remove_audio_effect = out_remove_audio_effect; + out->stream.get_latency = out_get_latency; + out->stream.set_volume = out_set_volume; + out->stream.write = out_write; + out->stream.get_render_position = out_get_render_position; + out->stream.get_next_write_timestamp = out_get_next_write_timestamp; + + out->dev = adev; + out->device = devices; + adev->output = (struct audio_stream_out *)out; + *stream_out = &out->stream; + +error: + pthread_mutex_unlock(&adev->lock); + + return ret; +} + +static void adev_close_output_stream(struct audio_hw_device *dev, + struct audio_stream_out *stream) { + struct generic_audio_device *adev = (struct generic_audio_device *)dev; + + pthread_mutex_lock(&adev->lock); + if (stream == adev->output) { + free(stream); + adev->output = NULL; + } + pthread_mutex_unlock(&adev->lock); +} + +static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) { + return 0; +} + +static char *adev_get_parameters(const struct audio_hw_device *dev, + const char *keys) { + return strdup(""); +} + +static int adev_init_check(const struct audio_hw_device *dev) { + return 0; +} + +static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) { + return 0; +} + +static int adev_set_master_volume(struct audio_hw_device *dev, float volume) { + return -ENOSYS; +} + +static int adev_get_master_volume(struct audio_hw_device *dev, float *volume) { + return -ENOSYS; +} + +static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) { + return -ENOSYS; +} + +static int adev_get_master_mute(struct audio_hw_device *dev, bool *muted) { + return -ENOSYS; +} + +static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) { + return 0; +} + +static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) { + struct generic_audio_device *adev = (struct generic_audio_device *)dev; + + pthread_mutex_lock(&adev->lock); + adev->mic_mute = state; + pthread_mutex_unlock(&adev->lock); + return 0; +} + +static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) { + struct generic_audio_device *adev = (struct generic_audio_device *)dev; + + pthread_mutex_lock(&adev->lock); + *state = adev->mic_mute; + pthread_mutex_unlock(&adev->lock); + + return 0; +} + +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, + const struct audio_config *config) { + return IN_BUFFER_SIZE; +} + +static int adev_open_input_stream(struct audio_hw_device *dev, + audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config, + struct audio_stream_in **stream_in, + audio_input_flags_t flags __unused, + const char *address __unused, + audio_source_t source __unused) { + struct generic_audio_device *adev = (struct generic_audio_device *)dev; + struct generic_stream_in *in; + int ret = 0, fd = 0; + + pthread_mutex_lock(&adev->lock); + if (adev->input != NULL) { + ret = -ENOSYS; + goto error; + } + + if ((config->format != AUDIO_FORMAT_PCM_16_BIT) || + (config->channel_mask != AUDIO_CHANNEL_IN_MONO) || + (config->sample_rate != IN_SAMPLING_RATE)) { + ALOGE("Error opening input stream format %d, channel_mask %04x, sample_rate %u", + config->format, config->channel_mask, config->sample_rate); + config->format = AUDIO_FORMAT_PCM_16_BIT; + config->channel_mask = AUDIO_CHANNEL_IN_MONO; + config->sample_rate = IN_SAMPLING_RATE; + ret = -EINVAL; + goto error; + } + + fd = connect_audio_server(anbox::audio::ClientInfo::Type::Recording); + if (fd < 0) { + ret = fd; + ALOGE("Failed to connect with Anbox audio servers (err %d)", ret); + goto error; + } + + in = (struct generic_stream_in *)calloc(1, sizeof(struct generic_stream_in)); + in->fd = fd; + + in->stream.common.get_sample_rate = in_get_sample_rate; + in->stream.common.set_sample_rate = in_set_sample_rate; + in->stream.common.get_buffer_size = in_get_buffer_size; + in->stream.common.get_channels = in_get_channels; + in->stream.common.get_format = in_get_format; + in->stream.common.set_format = in_set_format; + in->stream.common.standby = in_standby; + in->stream.common.dump = in_dump; + in->stream.common.set_parameters = in_set_parameters; + in->stream.common.get_parameters = in_get_parameters; + in->stream.common.add_audio_effect = in_add_audio_effect; + in->stream.common.remove_audio_effect = in_remove_audio_effect; + in->stream.set_gain = in_set_gain; + in->stream.read = in_read; + in->stream.get_input_frames_lost = in_get_input_frames_lost; + + in->dev = adev; + in->device = devices; + adev->input = (struct audio_stream_in *)in; + *stream_in = &in->stream; + +error: + pthread_mutex_unlock(&adev->lock); + + return ret; +} + +static void adev_close_input_stream(struct audio_hw_device *dev, + struct audio_stream_in *stream) { + struct generic_audio_device *adev = (struct generic_audio_device *)dev; + + pthread_mutex_lock(&adev->lock); + if (stream == adev->input) { + free(stream); + adev->input = NULL; + } + pthread_mutex_unlock(&adev->lock); +} + +static int adev_dump(const audio_hw_device_t *dev, int fd) { + struct generic_audio_device *adev = (struct generic_audio_device *)dev; + + const size_t SIZE = 256; + char buffer[SIZE]; + + dprintf(fd, + "\nadev_dump:\n" + "\tmic_mute: %s\n" + "\toutput: %p\n" + "\tinput: %p\n\n", + adev->mic_mute ? "true" : "false", + adev->output, + adev->input); + + if (adev->output != NULL) + out_dump((const struct audio_stream *)adev->output, fd); + if (adev->input != NULL) + in_dump((const struct audio_stream *)adev->input, fd); + + return 0; +} + +static int adev_close(hw_device_t *dev) { + struct generic_audio_device *adev = (struct generic_audio_device *)dev; + + adev_close_output_stream((struct audio_hw_device *)dev, adev->output); + adev_close_input_stream((struct audio_hw_device *)dev, adev->input); + + free(dev); + return 0; +} + +static int adev_open(const hw_module_t *module, const char *name, + hw_device_t **device) { + struct generic_audio_device *adev; + + if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) + return -EINVAL; + + adev = (struct generic_audio_device*) calloc(1, sizeof(struct generic_audio_device)); + + adev->device.common.tag = HARDWARE_DEVICE_TAG; + adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0; + adev->device.common.module = (struct hw_module_t *)module; + adev->device.common.close = adev_close; + + adev->device.init_check = adev_init_check; + adev->device.set_voice_volume = adev_set_voice_volume; + adev->device.set_master_volume = adev_set_master_volume; + adev->device.get_master_volume = adev_get_master_volume; + adev->device.set_master_mute = adev_set_master_mute; + adev->device.get_master_mute = adev_get_master_mute; + adev->device.set_mode = adev_set_mode; + adev->device.set_mic_mute = adev_set_mic_mute; + adev->device.get_mic_mute = adev_get_mic_mute; + adev->device.set_parameters = adev_set_parameters; + adev->device.get_parameters = adev_get_parameters; + adev->device.get_input_buffer_size = adev_get_input_buffer_size; + adev->device.open_output_stream = adev_open_output_stream; + adev->device.close_output_stream = adev_close_output_stream; + adev->device.open_input_stream = adev_open_input_stream; + adev->device.close_input_stream = adev_close_input_stream; + adev->device.dump = adev_dump; + + *device = &adev->device.common; + + return 0; +} + +static struct hw_module_methods_t hal_module_methods = { + .open = adev_open, +}; + +struct audio_module HAL_MODULE_INFO_SYM = { + .common = { + .tag = HARDWARE_MODULE_TAG, + .module_api_version = AUDIO_MODULE_API_VERSION_0_1, + .hal_api_version = HARDWARE_HAL_API_VERSION, + .id = AUDIO_HARDWARE_MODULE_ID, + .name = "Anbox audio HW HAL", + .author = "The Android Open Source Project", + .methods = &hal_module_methods, + }, +}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d47a59b4..1c545012 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -136,14 +136,20 @@ set(SOURCES anbox/graphics/emugl/TimeUtils.cpp anbox/graphics/emugl/WindowSurface.cpp + anbox/audio/server.cpp + anbox/audio/client_info.h + anbox/audio/source.h + anbox/audio/sink.h + anbox/wm/display.cpp anbox/wm/task.cpp anbox/wm/stack.cpp anbox/wm/manager.cpp anbox/wm/window_state.cpp anbox/wm/window.cpp - anbox/wm/platform_policy.cpp - anbox/wm/default_platform_policy.cpp + + anbox/platform/policy.cpp + anbox/platform/default_policy.cpp anbox/input/manager.cpp anbox/input/device.cpp @@ -168,6 +174,7 @@ set(SOURCES anbox/ubuntu/window.cpp anbox/ubuntu/keycode_converter.cpp anbox/ubuntu/platform_policy.cpp + anbox/ubuntu/audio_sink.cpp anbox/dbus/interface.h anbox/dbus/skeleton/service.cpp diff --git a/src/anbox/audio/client_info.h b/src/anbox/audio/client_info.h new file mode 100644 index 00000000..29900f81 --- /dev/null +++ b/src/anbox/audio/client_info.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_AUDIO_CLIENT_INFO_H_ +#define ANBOX_AUDIO_CLIENT_INFO_H_ + +#include + +namespace anbox { +namespace audio { +struct ClientInfo { + enum class Type : std::uint8_t { + Playback = 0, + Recording = 1, + Max = 2, + }; + Type type; +}; +} // namespace audio +} // namespace anbox + +#endif diff --git a/src/anbox/audio/server.cpp b/src/anbox/audio/server.cpp new file mode 100644 index 00000000..79cd2e35 --- /dev/null +++ b/src/anbox/audio/server.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/audio/server.h" +#include "anbox/audio/sink.h" +#include "anbox/network/published_socket_connector.h" +#include "anbox/network/delegate_connection_creator.h" +#include "anbox/network/local_socket_messenger.h" +#include "anbox/network/message_processor.h" +#include "anbox/common/type_traits.h" +#include "anbox/config.h" +#include "anbox/utils.h" +#include "anbox/logger.h" + +using namespace std::placeholders; + +namespace { +class AudioForwarder : public anbox::network::MessageProcessor { + public: + AudioForwarder(const std::shared_ptr &sink) : + sink_(sink) { + } + + bool process_data(const std::vector &data) override { + sink_->write_data(data); + return true; + } + + private: + std::shared_ptr sink_; +}; +} + +namespace anbox { +namespace audio { +Server::Server(const std::shared_ptr& rt, const std::shared_ptr &platform_policy) : + platform_policy_(platform_policy), + socket_file_(utils::string_format("%s/anbox_audio", config::socket_path())), + connector_(std::make_shared( + socket_file_, rt, + std::make_shared>(std::bind(&Server::create_connection_for, this, _1)))), + connections_(std::make_shared>()), + next_id_(0) { + + // FIXME: currently creating the socket creates it with the rights of + // the user we're running as. As this one is mapped into the container + ::chmod(socket_file_.c_str(), 0777); +} + +Server::~Server() {} + +void Server::create_connection_for(std::shared_ptr> const& socket) { + auto const messenger = + std::make_shared(socket); + + // We have to read the client flags first before we can continue + // processing the actual commands + ClientInfo client_info; + auto err = messenger->receive_msg( + boost::asio::buffer(&client_info, sizeof(ClientInfo))); + if (err) { + ERROR("Failed to read client info: %s", err.message()); + return; + } + + std::shared_ptr processor; + + switch (client_info.type) { + case ClientInfo::Type::Playback: + processor = std::make_shared(platform_policy_->create_audio_sink()); + break; + case ClientInfo::Type::Recording: + break; + default: + ERROR("Invalid client type %d", static_cast(client_info.type)); + return; + } + + // Everything ok, so approve the client by sending the requesting client + // info back. Once we have more things to negotiate we will send a modified + // client info struct back. + messenger->send(reinterpret_cast(&client_info), sizeof(client_info)); + + auto connection = std::make_shared( + messenger, messenger, next_id(), connections_, processor); + connections_->add(connection); + + connection->read_next_message(); +} + +int Server::next_id() { + return next_id_.fetch_add(1); +} +} // namespace audio +} // namespace anbox diff --git a/src/anbox/audio/server.h b/src/anbox/audio/server.h new file mode 100644 index 00000000..6a49764b --- /dev/null +++ b/src/anbox/audio/server.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_AUDIO_SERVER_H_ +#define ANBOX_AUDIO_SERVER_H_ + +#include "anbox/runtime.h" +#include "anbox/audio/client_info.h" +#include "anbox/network/socket_messenger.h" +#include "anbox/network/socket_connection.h" +#include "anbox/platform/policy.h" + +#include + +namespace anbox { +namespace network { +class PublishedSocketConnector; +} // namespace network +namespace audio { +class Server { + public: + Server(const std::shared_ptr& rt, const std::shared_ptr &platform_policy); + ~Server(); + + std::string socket_file() const { return socket_file_; } + + private: + void create_connection_for(std::shared_ptr> const& socket); + + int next_id(); + + std::shared_ptr platform_policy_; + std::string socket_file_; + std::shared_ptr connector_; + std::shared_ptr> const connections_; + std::atomic next_id_; +}; +} // namespace audio +} // namespace anbox + +#endif diff --git a/src/anbox/audio/sink.h b/src/anbox/audio/sink.h new file mode 100644 index 00000000..39e1b325 --- /dev/null +++ b/src/anbox/audio/sink.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_AUDIO_SINK_H_ +#define ANBOX_AUDIO_SINK_H_ + +#include + +#include + +namespace anbox { +namespace audio { +class Sink { + public: + virtual ~Sink() {} + virtual void write_data(const std::vector &data) = 0; +}; +} // namespace audio +} // namespace anbox + +#endif diff --git a/src/anbox/audio/source.h b/src/anbox/audio/source.h new file mode 100644 index 00000000..72dcc320 --- /dev/null +++ b/src/anbox/audio/source.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_AUDIO_SOURCE_H_ +#define ANBOX_AUDIO_SOURCE_H_ + +#include + +#include + +namespace anbox { +namespace audio { +class Source { + public: + virtual ~Source() {} + + virtual void read_data(std::vector &data) = 0; +}; +} // namespace audio +} // namespace anbox + +#endif diff --git a/src/anbox/cmds/run.cpp b/src/anbox/cmds/run.cpp index 88024599..87c2d175 100644 --- a/src/anbox/cmds/run.cpp +++ b/src/anbox/cmds/run.cpp @@ -20,6 +20,7 @@ #include "core/posix/signal.h" #include "anbox/application/launcher_storage.h" +#include "anbox/audio/server.h" #include "anbox/bridge/android_api_stub.h" #include "anbox/bridge/platform_api_skeleton.h" #include "anbox/bridge/platform_message_processor.h" @@ -122,6 +123,8 @@ anbox::cmds::Run::Run(const BusFactory &bus_factory) policy->set_renderer(gl_server->renderer()); + auto audio_server = std::make_shared(rt, policy); + // The qemu pipe is used as a very fast communication channel between guest // and host for things like the GLES emulation/translation, the RIL or ADB. auto qemu_pipe_connector = @@ -154,6 +157,7 @@ anbox::cmds::Run::Run(const BusFactory &bus_factory) container_configuration.bind_mounts = { {qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"}, {bridge_connector->socket_file(), "/dev/anbox_bridge"}, + {audio_server->socket_file(), "/dev/anbox_audio"}, {config::host_input_device_path(), "/dev/input"}, {"/dev/binder", "/dev/binder"}, {"/dev/ashmem", "/dev/ashmem"}, diff --git a/src/anbox/graphics/buffer_queue.cpp b/src/anbox/graphics/buffer_queue.cpp index 664713cd..1f18d5ec 100644 --- a/src/anbox/graphics/buffer_queue.cpp +++ b/src/anbox/graphics/buffer_queue.cpp @@ -47,6 +47,17 @@ int BufferQueue::push_locked( return try_push_locked(std::move(buffer)); } +int BufferQueue::wait_until_not_empty_locked(std::unique_lock &lock) { + while (count_ == 0) { + if (closed_) + // Closed queue is empty. + return -EIO; + can_pop_.wait(lock); + } + + return 0; +} + int BufferQueue::try_pop_locked(Buffer *buffer) { if (count_ == 0) return closed_ ? -EIO : -EAGAIN; diff --git a/src/anbox/graphics/buffer_queue.h b/src/anbox/graphics/buffer_queue.h index 20f0ba6a..6060a84f 100644 --- a/src/anbox/graphics/buffer_queue.h +++ b/src/anbox/graphics/buffer_queue.h @@ -33,6 +33,8 @@ class BufferQueue { bool can_pop_locked() const { return count_ > 0U; } bool is_closed_locked() const { return closed_; } + int wait_until_not_empty_locked(std::unique_lock &lock); + int try_push_locked(Buffer &&buffer); int push_locked(Buffer &&buffer, std::unique_lock &lock); int try_pop_locked(Buffer *buffer); diff --git a/src/anbox/graphics/buffered_io_stream.cpp b/src/anbox/graphics/buffered_io_stream.cpp index cf638180..9be469b6 100644 --- a/src/anbox/graphics/buffered_io_stream.cpp +++ b/src/anbox/graphics/buffered_io_stream.cpp @@ -115,7 +115,7 @@ void BufferedIOStream::thread_main() { std::unique_lock l(out_lock_); Buffer buffer; - auto result = out_queue_.pop_locked(&buffer, l); + const auto result = out_queue_.pop_locked(&buffer, l); if (result != 0 && result != -EAGAIN) break; auto bytes_left = buffer.size(); diff --git a/src/anbox/network/published_socket_connector.h b/src/anbox/network/published_socket_connector.h index 068f070b..1791f532 100644 --- a/src/anbox/network/published_socket_connector.h +++ b/src/anbox/network/published_socket_connector.h @@ -41,8 +41,7 @@ class PublishedSocketConnector : public DoNotCopyOrMove, public Connector { private: void start_accept(); void on_new_connection( - std::shared_ptr const& - socket, + std::shared_ptr const& socket, boost::system::error_code const& err); const std::string socket_file_; diff --git a/src/anbox/wm/default_platform_policy.cpp b/src/anbox/platform/default_policy.cpp similarity index 74% rename from src/anbox/wm/default_platform_policy.cpp rename to src/anbox/platform/default_policy.cpp index cfd11e43..d82c75c7 100644 --- a/src/anbox/wm/default_platform_policy.cpp +++ b/src/anbox/platform/default_policy.cpp @@ -15,9 +15,9 @@ * */ -#include "anbox/wm/default_platform_policy.h" -#include "anbox/logger.h" +#include "anbox/platform/default_policy.h" #include "anbox/wm/window.h" +#include "anbox/logger.h" namespace { class NullWindow : public anbox::wm::Window { @@ -29,12 +29,22 @@ class NullWindow : public anbox::wm::Window { } namespace anbox { -namespace wm { -DefaultPlatformPolicy::DefaultPlatformPolicy() {} +namespace platform { +DefaultPolicy::DefaultPolicy() {} -std::shared_ptr DefaultPlatformPolicy::create_window( +std::shared_ptr DefaultPolicy::create_window( const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) { return std::make_shared<::NullWindow>(task, frame); } + +std::shared_ptr DefaultPolicy::create_audio_sink() { + ERROR("Not implemented"); + return nullptr; +} + +std::shared_ptr DefaultPolicy::create_audio_source() { + ERROR("Not implemented"); + return nullptr; +} } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/default_platform_policy.h b/src/anbox/platform/default_policy.h similarity index 69% rename from src/anbox/wm/default_platform_policy.h rename to src/anbox/platform/default_policy.h index 22095062..45f96b50 100644 --- a/src/anbox/wm/default_platform_policy.h +++ b/src/anbox/platform/default_policy.h @@ -15,19 +15,21 @@ * */ -#ifndef ANBOX_WM_DEFAULT_PLATFORM_POLICY_H_ -#define ANBOX_WM_DEFAULT_PLATFORM_POLICY_H_ +#ifndef ANBOX_PLATFORM_DEFAULT_POLICY_H_ +#define ANBOX_PLATFORM_DEFAULT_POLICY_H_ -#include "anbox/wm/platform_policy.h" +#include "anbox/platform/policy.h" namespace anbox { -namespace wm { -class DefaultPlatformPolicy : public PlatformPolicy { +namespace platform { +class DefaultPolicy : public Policy { public: - DefaultPlatformPolicy(); - std::shared_ptr create_window( + DefaultPolicy(); + std::shared_ptr create_window( const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) override; + std::shared_ptr create_audio_sink() override; + std::shared_ptr create_audio_source() override; }; } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/platform_policy.cpp b/src/anbox/platform/policy.cpp similarity index 89% rename from src/anbox/wm/platform_policy.cpp rename to src/anbox/platform/policy.cpp index daf55b99..8cc41ff8 100644 --- a/src/anbox/wm/platform_policy.cpp +++ b/src/anbox/platform/policy.cpp @@ -15,10 +15,10 @@ * */ -#include "anbox/wm/platform_policy.h" +#include "anbox/platform/policy.h" namespace anbox { -namespace wm { -PlatformPolicy::~PlatformPolicy() {} +namespace platform { +Policy::~Policy() {} } // namespace wm } // namespace anbox diff --git a/src/anbox/wm/platform_policy.h b/src/anbox/platform/policy.h similarity index 70% rename from src/anbox/wm/platform_policy.h rename to src/anbox/platform/policy.h index 4fb286f5..3daf4c99 100644 --- a/src/anbox/wm/platform_policy.h +++ b/src/anbox/platform/policy.h @@ -15,8 +15,8 @@ * */ -#ifndef ANBOX_WM_PLATFORM_POLICY_H_ -#define ANBOX_WM_PLATFORM_POLICY_H_ +#ifndef ANBOX_PLATFORM_POLICY_H_ +#define ANBOX_PLATFORM_POLICY_H_ #include "anbox/graphics/rect.h" #include "anbox/wm/window_state.h" @@ -24,14 +24,23 @@ #include namespace anbox { +namespace audio { +class Sink; +class Source; +} // namespace audio namespace wm { class Window; -class PlatformPolicy { +} // namespace wm +namespace platform { +class Policy { public: - virtual ~PlatformPolicy(); + virtual ~Policy(); - virtual std::shared_ptr create_window( + virtual std::shared_ptr create_window( const anbox::wm::Task::Id &task, const anbox::graphics::Rect &frame) = 0; + + virtual std::shared_ptr create_audio_sink() = 0; + virtual std::shared_ptr create_audio_source() = 0; }; } // namespace wm } // namespace anbox diff --git a/src/anbox/ubuntu/audio_sink.cpp b/src/anbox/ubuntu/audio_sink.cpp new file mode 100644 index 00000000..a4d30053 --- /dev/null +++ b/src/anbox/ubuntu/audio_sink.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/ubuntu/audio_sink.h" +#include "anbox/logger.h" + +#include + +#include + +namespace { +const constexpr size_t max_queue_size{16}; +} + +namespace anbox { +namespace ubuntu { +AudioSink::AudioSink() : + device_id_(0), + queue_(max_queue_size) { +} + +AudioSink::~AudioSink() {} + +void AudioSink::on_data_requested(void *user_data, std::uint8_t *buffer, int size) { + auto thiz = static_cast(user_data); + thiz->read_data(buffer, size); +} + +bool AudioSink::connect_audio() { + if (device_id_ > 0) + return true; + + SDL_memset(&spec_, 0, sizeof(spec_)); + spec_.freq = 44100; + spec_.format = AUDIO_S16; + spec_.channels = 2; + spec_.samples = 4096; + spec_.callback = &AudioSink::on_data_requested; + spec_.userdata = this; + + device_id_ = SDL_OpenAudioDevice(nullptr, 0, &spec_, nullptr, 0); + if (!device_id_) + return false; + + SDL_PauseAudioDevice(device_id_, 0); + + return true; +} + +void AudioSink::disconnect_audio() { + if (device_id_ == 0) + return; + + SDL_CloseAudioDevice(device_id_); + device_id_ = 0; +} + +void AudioSink::read_data(std::uint8_t *buffer, int size) { + std::unique_lock l(lock_); + const auto wanted = size; + size_t count = 0; + auto dst = buffer; + + while (count < wanted) { + if (read_buffer_left_ > 0) { + size_t avail = std::min(wanted - count, read_buffer_left_); + memcpy(dst + count, + read_buffer_.data() + (read_buffer_.size() - read_buffer_left_), + avail); + count += avail; + read_buffer_left_ -= avail; + continue; + } + + bool blocking = (count == 0); + auto result = -EIO; + if (blocking) + result = queue_.pop_locked(&read_buffer_, l); + else + result = queue_.try_pop_locked(&read_buffer_); + + if (result == 0) { + read_buffer_left_ = read_buffer_.size(); + continue; + } + + if (count > 0) break; + + return; + } +} + +void AudioSink::write_data(const std::vector &data) { + std::unique_lock l(lock_); + if (!connect_audio()) { + WARNING("Audio server not connected, skipping %d bytes", data.size()); + return; + } + graphics::Buffer buffer{data.data(), data.data() + data.size()}; + queue_.push_locked(std::move(buffer), l); +} +} // namespace ubuntu +} // namespace anbox diff --git a/src/anbox/ubuntu/audio_sink.h b/src/anbox/ubuntu/audio_sink.h new file mode 100644 index 00000000..1a597a08 --- /dev/null +++ b/src/anbox/ubuntu/audio_sink.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_UBUNTU_AUDIO_SINK_H_ +#define ANBOX_UBUNTU_AUDIO_SINK_H_ + +#include "anbox/audio/sink.h" +#include "anbox/graphics/buffer_queue.h" + +#include + +#include + +namespace anbox { +namespace ubuntu { +class AudioSink : public audio::Sink { + public: + AudioSink(); + ~AudioSink(); + + void write_data(const std::vector &data) override; + + private: + bool connect_audio(); + void disconnect_audio(); + void read_data(std::uint8_t *buffer, int size); + + static void on_data_requested(void *user_data, std::uint8_t *buffer, int size); + + std::mutex lock_; + SDL_AudioSpec spec_; + SDL_AudioDeviceID device_id_; + graphics::BufferQueue queue_; + graphics::Buffer read_buffer_; + size_t read_buffer_left_ = 0; +}; +} // namespace ubuntu +} // namespace anbox + +#endif diff --git a/src/anbox/ubuntu/platform_policy.cpp b/src/anbox/ubuntu/platform_policy.cpp index ae01d7eb..4ca2f44f 100644 --- a/src/anbox/ubuntu/platform_policy.cpp +++ b/src/anbox/ubuntu/platform_policy.cpp @@ -22,6 +22,7 @@ #include "anbox/logger.h" #include "anbox/ubuntu/keycode_converter.h" #include "anbox/ubuntu/window.h" +#include "anbox/ubuntu/audio_sink.h" #include @@ -36,7 +37,7 @@ PlatformPolicy::PlatformPolicy( : input_manager_(input_manager), android_api_(android_api), event_thread_running_(false) { - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_EVENTS) < 0) BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize SDL")); auto display_frame = graphics::Rect::Invalid; @@ -263,5 +264,14 @@ void PlatformPolicy::window_resized(const Window::Id &id, DisplayManager::DisplayInfo PlatformPolicy::display_info() const { return display_info_; } + +std::shared_ptr PlatformPolicy::create_audio_sink() { + return std::make_shared(); +} + +std::shared_ptr PlatformPolicy::create_audio_source() { + ERROR("Not implemented"); + return nullptr; +} } // namespace wm } // namespace anbox diff --git a/src/anbox/ubuntu/platform_policy.h b/src/anbox/ubuntu/platform_policy.h index 0679aa91..8695f7fb 100644 --- a/src/anbox/ubuntu/platform_policy.h +++ b/src/anbox/ubuntu/platform_policy.h @@ -19,7 +19,7 @@ #define ANBOX_UBUNTU_PLATFORM_POLICY_H_ #include "anbox/ubuntu/window.h" -#include "anbox/wm/platform_policy.h" +#include "anbox/platform/policy.h" #include "anbox/graphics/emugl/DisplayManager.h" @@ -40,7 +40,7 @@ class AndroidApiStub; } // namespace bridge namespace ubuntu { class PlatformPolicy : public std::enable_shared_from_this, - public wm::PlatformPolicy, + public platform::Policy, public Window::Observer, public DisplayManager { public: @@ -63,6 +63,9 @@ class PlatformPolicy : public std::enable_shared_from_this, void set_renderer(const std::shared_ptr &renderer); + std::shared_ptr create_audio_sink() override; + std::shared_ptr create_audio_source() override; + private: void process_events(); void process_input_event(const SDL_Event &event); diff --git a/src/anbox/wm/manager.cpp b/src/anbox/wm/manager.cpp index fbd58b9a..25b9d80d 100644 --- a/src/anbox/wm/manager.cpp +++ b/src/anbox/wm/manager.cpp @@ -16,15 +16,15 @@ */ #include "anbox/wm/manager.h" +#include "anbox/platform/policy.h" #include "anbox/logger.h" -#include "anbox/wm/platform_policy.h" #include namespace anbox { namespace wm { -Manager::Manager(const std::shared_ptr &platform) - : platform_(platform) {} +Manager::Manager(const std::shared_ptr &policy) + : platform_policy_(policy) {} Manager::~Manager() {} @@ -61,7 +61,7 @@ void Manager::apply_window_state_update(const WindowState::List &updated, } auto platform_window = - platform_->create_window(window.task(), window.frame()); + platform_policy_->create_window(window.task(), window.frame()); platform_window->attach(); windows_.insert({window.task(), platform_window}); } diff --git a/src/anbox/wm/manager.h b/src/anbox/wm/manager.h index 823547f9..5e81024a 100644 --- a/src/anbox/wm/manager.h +++ b/src/anbox/wm/manager.h @@ -26,11 +26,13 @@ #include namespace anbox { +namespace platform { +class Policy; +} // namespace platform namespace wm { -class PlatformPolicy; class Manager { public: - Manager(const std::shared_ptr &platform); + Manager(const std::shared_ptr &policy); ~Manager(); void apply_window_state_update(const WindowState::List &updated, @@ -40,7 +42,7 @@ class Manager { private: std::mutex mutex_; - std::shared_ptr platform_; + std::shared_ptr platform_policy_; std::map> windows_; }; } // namespace wm diff --git a/tests/anbox/graphics/layer_composer_tests.cpp b/tests/anbox/graphics/layer_composer_tests.cpp index c0eff825..2ed0394c 100644 --- a/tests/anbox/graphics/layer_composer_tests.cpp +++ b/tests/anbox/graphics/layer_composer_tests.cpp @@ -20,7 +20,7 @@ #include #include -#include "anbox/wm/default_platform_policy.h" +#include "anbox/platform/default_policy.h" #include "anbox/wm/manager.h" #include "anbox/wm/window_state.h" @@ -43,7 +43,7 @@ TEST(LayerComposer, FindsNoSuitableWindowForLayer) { // The default policy will create a dumb window instance when requested // from the manager. - auto platform_policy = std::make_shared(); + auto platform_policy = std::make_shared(); auto wm = std::make_shared(platform_policy); auto single_window = wm::WindowState{ @@ -76,7 +76,7 @@ TEST(LayerComposer, MapsLayersToWindows) { // The default policy will create a dumb window instance when requested // from the manager. - auto platform_policy = std::make_shared(); + auto platform_policy = std::make_shared(); auto wm = std::make_shared(platform_policy); auto first_window = wm::WindowState{ @@ -135,7 +135,7 @@ TEST(LayerComposer, WindowPartiallyOffscreen) { // The default policy will create a dumb window instance when requested // from the manager. - auto platform_policy = std::make_shared(); + auto platform_policy = std::make_shared(); auto wm = std::make_shared(platform_policy); auto window = wm::WindowState{ @@ -179,7 +179,7 @@ TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) { // The default policy will create a dumb window instance when requested // from the manager. - auto platform_policy = std::make_shared(); + auto platform_policy = std::make_shared(); auto wm = std::make_shared(platform_policy); auto window = wm::WindowState{ -- GitLab