/*
* Copyright (C) 2016 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.
*/
#pragma once
#include <list>
#include <map>
#include <memory>
#include "common/libs/fs/shared_fd.h"
#include "common/libs/threads/cuttlefish_thread.h"
#include "common/vsoc/lib/audio_data_region_view.h"
#include "common/vsoc/lib/vsoc_audio_message.h"
#include "guest/hals/audio/audio_hal.h"
#include "guest/hals/audio/vsoc_audio_input_stream.h"
#include "guest/libs/platform_support/api_level_fixes.h"
namespace cvd {
class GceAudioInputStream;
class GceAudioOutputStream;
class GceAudio : public audio_hw_device {
public:
// This common code manipulates the parameters of input and output streams.
static int SetStreamParameters(struct audio_stream *, const char *);
~GceAudio();
// Non-HAL methods that are part of the GCE implementation.
// Most of these are used by the input and output streams.
// Returns true if the microphone is muted. Used by input streams.
bool IsMicrophoneMuted() {
cvd::LockGuard<cvd::Mutex> guard(lock_);
return mic_muted_;
}
// Send a message to the connected streamer.
// Returns:
// 0 if there is no streamer.
// >0 if the message was sent.
// -1 if there was an error.
ssize_t SendMsg(const msghdr&, int flags);
// Sends a stream update to the connected streamer.
// Stream updates have no frames. Use SendMsg if the message has frames.
// 0 if there is no streamer.
// >0 if the message was sent.
// -1 if there was an error.
ssize_t SendStreamUpdate(
const gce_audio_message& stream_info, int flags);
// Callbacks for the Android audio_module HAL interface.
// Most of the comments below are copied from
// libhardware/include/hardware/audio.h
//
// Where the is a conflict the comments there apply.
// By default these methods return 0 on success -<errno> for failure.
// Opens the device.
static int Open(const hw_module_t* module, const char* name,
hw_device_t** device);
// Closes the device, closing any open input streams and output streams.
int Close();
// Closes the input stream, throwing away any data in the buffer.
void CloseInputStream(audio_stream_in* stream);
// Closes the output stream without waiting for the buffer to clear.
void CloseOutputStream(audio_stream_out* stream);
// Creates an audio patch between several source and sink ports.
// The handle is allocated by the HAL and should be unique for this
// audio HAL module.
// TODO(ghartman): Implement this as part of HAL 3.0
//int CreateAudioPatch(unsigned int num_sources,
// const struct audio_port_config *sources,
// unsigned int num_sinks,
// const struct audio_port_config *sinks,
// audio_patch_handle_t *handle);
// dumps the state of the audio hardware to the given fd.
// This information can be retrieved using the dumpsys utility.
int Dump(int fd) const;
// Fills the list of supported attributes for a given audio port.
// As input, "port" contains the information (type, role, address etc...)
// needed by the HAL to identify the port.
// As output, "port" contains possible attributes (sampling rates, formats,
// channel masks, gain controllers...) for this port.
// TODO(ghartman): Implement this as part of HAL 3.0
// int GetAudioPort(struct audio_port *port);
// Sets audio port configuration
// TODO(ghartman): Implement this as part of HAL 3.0
// int SetAudioPortConfig(const struct audio_port_config *config);
size_t GetInputBufferSize(const audio_config*) const;
// Gets the current master volume value for the HAL, if the HAL supports
// master volume control. AudioFlinger will query this value from the
// primary audio HAL when the service starts and use the value for setting
// the initial master volume across all HALs. HALs which do not support
// this method may leave it set to NULL.
int GetMasterVolume(float* /*volume*/);
// Get the current master mute status for the HAL, if the HAL supports
// master mute control. AudioFlinger will query this value from the primary
// audio HAL when the service starts and use the value for setting the
// initial master mute across all HALs. HALs which do not support this
// method may leave it set to NULL.
int GetMasterMute(bool* muted);
// Gets the audio mute status for the microphone.
int GetMicMute(bool* state) const;
// Retrieves the global audio parameters.
// TODO(ghartman): Implement this.
char* GetParameters(const char* keys) const;
// Enumerates what devices are supported by each audio_hw_device
// implementation.
// Return value is a bitmask of 1 or more values of audio_devices_t
// used by audio flinger.
// NOTE: audio HAL implementations starting with
// AUDIO_DEVICE_API_VERSION_2_0 do not implement this function.
// AUDIO_DEVICE_API_VERSION_2_0 was the current version as of JB-MR1
// All supported devices should be listed in audio_policy.conf
// file and the audio policy manager must choose the appropriate
// audio module based on information in this file.
uint32_t GetSupportedDevices() const;
// Checks to see if the audio hardware interface has been initialized.
// Always returns 0 to indicate success, but -ENODEV is also allowed to
// indicate failure.
int InitCheck() const;
// Creates an additional hardware input stream.
// Additional parameters were added in the 3.0 version of the HAL.
// These defaults make it easier to implement a cross-branch device.
int OpenInputStream(
audio_io_handle_t handle,
audio_devices_t devices, audio_config *config,
audio_stream_in **stream_in,
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
const char* address = 0,
audio_source_t source = AUDIO_SOURCE_DEFAULT);
// Creates an additional output stream.
// The "address" parameter qualifies the "devices" audio device type if
// needed. On GCE we ignore it for now because we simulate a single SoC
// hw devices.
//
// The format format depends on the device type:
// Bluetooth devices use the MAC address of the device in the form
// "00:11:22:AA:BB:CC"
// USB devices use the ALSA card and device numbers in the form
// "card=X;device=Y"
// Other devices may use a number or any other string.
int OpenOutputStream(
audio_io_handle_t handle,
audio_devices_t devices, audio_output_flags_t flags,
audio_config* config, audio_stream_out** stream_out,
const char* address = 0);
// Releases an audio patch.
// TODO(ghartman): Implement this as part of HAL 3.0
//int ReleaseAudioPatch(audio_patch_handle_t handle);
// Sets the audio mute status for all audio activities. If any value other
// than 0 is returned, the software mixer will emulate this capability.
// The GCE implementation always returns 0.
int SetMasterMute(bool muted);
// Sets the audio volume for all audio activities other than voice call.
// Range between 0.0 and 1.0. If any value other than 0 is returned,
// the software mixer will emulate this capability.
// The GCE implementation always returns 0.
int SetMasterVolume(float volume);
// Sets the audio mute status for the microphone.
int SetMicMute(bool state);
// set_mode is called when the audio mode changes. AUDIO_MODE_NORMAL mode
// is for standard audio playback, AUDIO_MODE_RINGTONE when a ringtone is
// playing, and AUDIO_MODE_IN_CALL when a call is in progress.
int SetMode(audio_mode_t mode);
// Sets the global audio parameters.
// TODO(ghartman): Create a sensible implementation.
int SetParameters(const char* kvpairs);
// Sets the audio volume of a voice call. Range is between 0.0 and 1.0
int SetVoiceVolume(float volume);
private:
// 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
// OpenOutputStream with default values for the paramteres that were added,
// and then generates a HAL-specific wrapper to be used in the function
// table.
#if defined(AUDIO_DEVICE_API_VERSION_3_0)
typedef int OpenInputStreamHAL_t(
audio_io_handle_t, audio_devices_t, audio_config*, audio_stream_in**,
audio_input_flags_t, const char*, audio_source_t);
int OpenInputStreamCurrentHAL(
audio_io_handle_t a, audio_devices_t b, audio_config* c,
audio_stream_in** d, audio_input_flags_t e, const char* f,
audio_source_t g) {
return OpenInputStream(a, b, c, d, e, f, g);
}
typedef int OpenOutputStreamHAL_t(
audio_io_handle_t, audio_devices_t, audio_output_flags_t,
audio_config*, audio_stream_out**,
const char*);
int OpenOutputStreamCurrentHAL(
audio_io_handle_t a, audio_devices_t b, audio_output_flags_t c,
audio_config* d, audio_stream_out** e,
const char* f) {
return OpenOutputStream(a, b, c, d, e, f);
}
#else
typedef int OpenInputStreamHAL_t(
audio_io_handle_t, audio_devices_t, audio_config*, audio_stream_in**);
int OpenInputStreamCurrentHAL(
audio_io_handle_t a, audio_devices_t b, audio_config* c,
audio_stream_in** d) {
return OpenInputStream(a, b, c, d);
}
typedef int OpenOutputStreamHAL_t(
audio_io_handle_t, audio_devices_t, audio_output_flags_t,
audio_config*, audio_stream_out**);
int OpenOutputStreamCurrentHAL(
audio_io_handle_t a, audio_devices_t b, audio_output_flags_t c,
audio_config* d, audio_stream_out** e) {
return OpenOutputStream(a, b, c, d, e);
}
#endif
//TODO(ghartman): Update this when we support 3.0.
#if defined(AUDIO_DEVICE_API_VERSION_2_0)
static const unsigned int version_ = AUDIO_DEVICE_API_VERSION_2_0;
#else
static const unsigned int version_ = AUDIO_DEVICE_API_VERSION_1_0;
#endif
using AudioDataRegionView = vsoc::audio_data::AudioDataRegionView;
AudioDataRegionView* audio_data_rv_{};
std::unique_ptr<vsoc::RegionWorker> audio_worker_;
// Lock to protect the data below.
mutable cvd::Mutex lock_;
// State that is managed at the device level.
float voice_volume_;
float master_volume_;
bool master_muted_;
bool mic_muted_;
audio_mode_t mode_;
// There can be multiple input and output streams. This field is used
// to assign each one a unique identifier.
// TODO(ghartman): This can wrap after 2^32 streams. Ideally we should check
// the output_list_ to ensure that the stream number hasn't been assigned.
// However, streams don't really appear and disapper that often.
// We use the same counter for both input and output streams to make things
// a little easier on the client.
uint32_t next_stream_number_;
// List of the currently active output streams.
// Used to clean things up Close()
std::list<GceAudioOutputStream *> output_list_;
// List of the currently active input streams.
// Used to clean things up Close()
typedef std::map<uint32_t, GceAudioInputStream *> input_map_t;
input_map_t input_map_;
GceAudio() :
audio_hw_device(),
voice_volume_(0.0),
master_volume_(0.0),
master_muted_(false),
mic_muted_(false),
mode_(AUDIO_MODE_NORMAL),
next_stream_number_(1) { }
};
}