From 5e8c7ea0515d571d711a9a1e7903313d6b481a3b Mon Sep 17 00:00:00 2001 From: Angela Stegmaier Date: Mon, 21 Oct 2013 14:16:11 -0500 Subject: audio: multizone: Add initial implementation Add the multizone AudioHAL support to jacinto6evm. The multizone audio is built if the multizone flag is set, otherwise the legacy AudioHAL is built. Change-Id: Ib0b401f963cd9327caeb73623bba163fe8129870 Signed-off-by: Angela Stegmaier Signed-off-by: Misael Lopez Cruz --- audio/multizone/Android.mk | 60 +++ audio/multizone/AudioHw.cpp | 873 ++++++++++++++++++++++++++++++++++++++ audio/multizone/AudioHw.h | 209 +++++++++ audio/multizone/audio_hw.cpp | 562 ++++++++++++++++++++++++ audio/multizone/audio_policy.conf | 116 +++++ audio/multizone/dra7evm_paths.xml | 110 +++++ 6 files changed, 1930 insertions(+) create mode 100644 audio/multizone/Android.mk create mode 100644 audio/multizone/AudioHw.cpp create mode 100644 audio/multizone/AudioHw.h create mode 100644 audio/multizone/audio_hw.cpp create mode 100644 audio/multizone/audio_policy.conf create mode 100644 audio/multizone/dra7evm_paths.xml (limited to 'audio/multizone') diff --git a/audio/multizone/Android.mk b/audio/multizone/Android.mk new file mode 100644 index 0000000..46ec26a --- /dev/null +++ b/audio/multizone/Android.mk @@ -0,0 +1,60 @@ +# Copyright (C) 2013 Texas Instruments +# +# 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_policy.conf +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +LOCAL_SRC_FILES := $(LOCAL_MODULE) +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := dra7evm_paths.xml +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +LOCAL_SRC_FILES := $(LOCAL_MODULE) +include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) + +LOCAL_MODULE := audio.primary.$(TARGET_BOARD_PLATFORM) + +LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw + +LOCAL_SRC_FILES := \ + AudioHw.cpp \ + audio_hw.cpp + +LOCAL_C_INCLUDES += \ + system/media/audio_utils/include \ + system/media/audio_effects/include \ + device/ti/common-open/audio/utils/include + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libtiaudioutils \ + libutils + +LOCAL_SHARED_LIBRARIES += libstlport +include external/stlport/libstlport.mk + +LOCAL_STATIC_LIBRARIES := libmedia_helper + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_SHARED_LIBRARY) diff --git a/audio/multizone/AudioHw.cpp b/audio/multizone/AudioHw.cpp new file mode 100644 index 0000000..78caf77 --- /dev/null +++ b/audio/multizone/AudioHw.cpp @@ -0,0 +1,873 @@ +/* + * Copyright (C) 2013 Texas Instruments + * + * 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 "AudioHw" +// #define LOG_NDEBUG 0 +// #define VERY_VERBOSE_LOGGING +#ifdef VERY_VERBOSE_LOGGING +#define ALOGVV ALOGV +#else +#define ALOGVV(...) do { } while(0) +#endif + +#include + +#include + +#include + +namespace android { + +AudioStreamOut::AudioStreamOut(AudioHwDevice *hwDev, + PcmWriter *writer, + const PcmParams ¶ms, + const SlotMap &map, + audio_devices_t devices) + : mHwDev(hwDev), mWriter(writer), + mParams(params), mDevices(devices), mStandby(true) +{ + if (mWriter) + mStream = new AdaptedOutStream(params, map); +} + +int AudioStreamOut::initCheck() const +{ + int ret = 0; + + if (!mHwDev) { + ALOGE("AudioStreamOut: initCheck() invalid AudioHwDevice"); + ret = -ENODEV; + } + else if (!mWriter || !mWriter->initCheck()) { + ALOGE("AudioStreamOut: initCheck() invalid PCM writer"); + ret = -ENODEV; + } + else if (mStream == NULL || !mStream->initCheck()) { + ALOGE("AudioStreamOut: initCheck() invalid Out Stream"); + ret = -ENODEV; + } + + ALOGV("AudioStreamOut: init check %d", ret); + + return ret; +} + +uint32_t AudioStreamOut::getSampleRate() const +{ + uint32_t rate = mParams.sampleRate; + + ALOGVV("AudioStreamOut: getSampleRate() %u Hz", rate); + + return rate; +} + +int AudioStreamOut::setSampleRate(uint32_t rate) +{ + ALOGV("AudioStreamOut: setSampleRate() %u Hz", rate); + + return 0; +} + +size_t AudioStreamOut::getBufferSize() const +{ + size_t size; + + /* Take resampling ratio into account and align to the nearest + * 16 frames as required by the AudioFlinger */ + size = (mParams.frameCount * mParams.sampleRate) / mWriter->getParams().sampleRate; + size = ((size + 15) & ~15) * mParams.frameSize(); + + ALOGVV("AudioStreamOut: getBufferSize() %u bytes", size); + + return size; +} + +audio_channel_mask_t AudioStreamOut::getChannels() const +{ + uint32_t channels = mParams.channels; + + ALOGVV("AudioStreamOut: getChannels() %u channels", channels); + + return audio_channel_out_mask_from_count(channels); +} + +audio_format_t AudioStreamOut::getFormat() const +{ + uint32_t sampleBits = mParams.sampleBits; + + ALOGVV("AudioStreamOut: getFormat() %u bits/sample", sampleBits); + + switch (sampleBits) { + case 8: + return AUDIO_FORMAT_PCM_8_BIT; + case 24: + return AUDIO_FORMAT_PCM_8_24_BIT; + case 32: + return AUDIO_FORMAT_PCM_32_BIT; + case 16: + default: + return AUDIO_FORMAT_PCM_16_BIT; + } +} + +int AudioStreamOut::setFormat(audio_format_t format) +{ + ALOGV("AudioStreamOut: setFormat() %u bits/sample", + audio_bytes_per_sample(format) * 8); + + return 0; +} + +int AudioStreamOut::standby() +{ + ALOGV("AudioStreamOut: standby()"); + + AutoMutex lock(mLock); + + if (!mStandby) { + mStream->stop(); + mWriter->unregisterStream(mStream); + mHwDev->mMixer.setPath(mDevices, false); + mStandby = true; + } + + return 0; +} + +int AudioStreamOut::dump(int fd) const +{ + ALOGV("AudioStreamOut: dump()"); + return 0; +} + +audio_devices_t AudioStreamOut::getDevice() const +{ + ALOGV("AudioStreamOut: getDevice()"); + return mDevices; +} + +int AudioStreamOut::setParameters(const char *kv_pairs) +{ + ALOGV("AudioStreamOut: setParameters() '%s'", kv_pairs ? kv_pairs : ""); + + int ret; + + AudioParameter parms = AudioParameter(String8(kv_pairs)); + String8 key = String8(AudioParameter::keyRouting); + int device; + + if ((ret = parms.getInt(key, device)) == NO_ERROR) { + if ((mDevices & AUDIO_DEVICE_OUT_ALL) != (unsigned int)device) { + standby(); + } + if (device & ~(mHwDev->getSupportedDevices())) { + ALOGW("AudioStreamOut: setParameters() device(s) not supported, " + "will use default devices"); + } + else + mDevices = device; + } + + return ret; +} + +char *AudioStreamOut::getParameters(const char *keys) const +{ + ALOGV("AudioStreamOut::getParameters()"); + return NULL; +} + +int AudioStreamOut::addAudioEffect(effect_handle_t effect) const +{ + ALOGV("AudioStreamOut: addAudioEffects()"); + return 0; +} + +int AudioStreamOut::removeAudioEffect(effect_handle_t effect) const +{ + ALOGV("AudioStreamOut: removeAudioEffects()"); + return 0; +} + +uint32_t AudioStreamOut::getLatency() const +{ + uint32_t latency = (1000 * getBufferSize()) / mWriter->getParams().sampleRate; + + ALOGVV("AudioStreamOut: getLatency() %u ms", latency); + + return latency; +} + +int AudioStreamOut::setVolume(float left, float right) +{ + ALOGV("AudioStreamOut: setVolume() left=%.4f right=%.4f", left, right); + return -ENOSYS; +} + +ssize_t AudioStreamOut::write(const void* buffer, size_t bytes) +{ + uint32_t frames = mParams.bytesToFrames(bytes); + int ret = 0; + uint32_t usecs = (frames * 1000000) / mParams.sampleRate; + + ALOGVV("AudioStreamOut: write %u frames (%u bytes) buffer %p", + frames, bytes, buffer); + + AutoMutex lock(mLock); + + if (mStandby) { + mHwDev->mMixer.setPath(mDevices, true); + ret = mWriter->registerStream(mStream); + if (ret) { + ALOGE("AudioStreamOut: failed to register stream %d", ret); + return ret; + } + ret = mStream->start(); + if (ret) { + ALOGE("AudioStreamOut: failed to start stream %d", ret); + mWriter->unregisterStream(mStream); + usleep(usecs); /* limits the rate of error messages */ + return ret; + } + + mStandby = false; + } + + ret = mStream->write(buffer, frames); + if (ret < 0) { + ALOGE("AudioStreamOut: failed to write data %d", ret); + usleep(usecs); + } else { + ALOGW_IF(ret != (int)frames, + "AudioStreamOut: wrote only %d out of %d requested frames", + ret, frames); + bytes = mParams.framesToBytes(ret); + } + + return bytes; +} + +int AudioStreamOut::getRenderPosition(uint32_t *dsp_frames) const +{ + ALOGV("AudioStreamOut: getRenderPosition()"); + + return -EINVAL; +} + +int AudioStreamOut::getNextWriteTimestamp(int64_t *timestamp) const +{ + ALOGVV("AudioStreamOut: getNextWriteTimestamp()"); + + return -EINVAL; +} + +/* ---------------------------------------------------------------------------------------- */ + +AudioStreamIn::AudioStreamIn(AudioHwDevice *hwDev, + PcmReader *reader, + const PcmParams ¶ms, + const SlotMap &map, + audio_devices_t devices) + : mHwDev(hwDev), mReader(reader), mParams(params), mDevices(devices), + mSource(AUDIO_SOURCE_DEFAULT), mStandby(true) +{ + if (mReader) + mStream = new AdaptedInStream(params, map); +} + +int AudioStreamIn::initCheck() const +{ + int ret = 0; + + if (!mHwDev) { + ALOGE("AudioStreamIn: initCheck() invalid AudioHwDevice"); + ret = -ENODEV; + } + else if (!mReader || !mReader->initCheck()) { + ALOGE("AudioStreamIn: initCheck() invalid PCM reader"); + ret = -ENODEV; + } + else if (mStream == NULL || !mStream->initCheck()) { + ALOGE("AudioStreamIn: initCheck() invalid In Stream"); + ret = -ENODEV; + } + + ALOGV("AudioStreamIn: init check %d", ret); + + return ret; +} + +uint32_t AudioStreamIn::getSampleRate() const +{ + ALOGV("AudioStreamIn: getSampleRate()"); + + uint32_t rate = mParams.sampleRate; + + return rate; +} + +int AudioStreamIn::setSampleRate(uint32_t rate) +{ + ALOGV("AudioStreamIn: setSampleRate() %u Hz", rate); + + return 0; +} + +size_t AudioStreamIn::getBufferSize() const +{ + size_t size; + + /* Take resampling ratio into account and align to the nearest + * 16 frames as required by the AudioFlinger */ + size = (mParams.frameCount * mParams.sampleRate) / mReader->getParams().sampleRate; + size = ((size + 15) & ~15) * mParams.frameSize(); + + ALOGVV("AudioStreamIn: getBufferSize() %u bytes", size); + + return size; +} + +audio_channel_mask_t AudioStreamIn::getChannels() const +{ + ALOGV("AudioStreamIn: getChannels()"); + + return audio_channel_in_mask_from_count(mParams.channels); +} + +audio_format_t AudioStreamIn::getFormat() const +{ + ALOGV("AudioStreamIn: getFormat()"); + + return AUDIO_FORMAT_PCM_16_BIT; +} + +int AudioStreamIn::setFormat(audio_format_t format) +{ + ALOGV("AudioStreamIn: setFormat()"); + + return 0; +} + +int AudioStreamIn::standby() +{ + ALOGV("AudioStreamIn: standby()"); + + AutoMutex lock(mLock); + + if (!mStandby) { + mStream->stop(); + mReader->unregisterStream(mStream); + mHwDev->mMixer.setPath(mDevices, false); + mStandby = true; + } + + return 0; +} + +int AudioStreamIn::dump(int fd) const +{ + ALOGV("AudioStreamIn: dump()"); + + return 0; +} + +audio_devices_t AudioStreamIn::getDevice() const +{ + ALOGV("AudioStreamIn: getDevice()"); + + return mDevices; +} + +int AudioStreamIn::setParameters(const char *kv_pairs) +{ + ALOGV("AudioStreamIn: setParameters() '%s'", kv_pairs ? kv_pairs : ""); + + int ret; + + AudioParameter parms = AudioParameter(String8(kv_pairs)); + String8 source_key = String8(AudioParameter::keyInputSource); + String8 device_key = String8(AudioParameter::keyRouting); + int source, device; + + if ((ret = parms.getInt(source_key, source)) == NO_ERROR) { + /* no audio source uses 0 */ + if ((mSource != (unsigned int)source) && + (source != 0) && + (source < AUDIO_SOURCE_CNT)) { + ALOGV("AudioStreamIn: setParameters() source changed [%d]->[%d]", + mSource, source); + mSource = (audio_source_t)source; + /* Nothing to do for AUDIO_PARAMETER_STREAM_INPUT_SOURCE, so only + * record the source and continue */ + } + } + + if ((ret = parms.getInt(device_key, device)) == NO_ERROR) { + if ((mDevices & AUDIO_DEVICE_IN_ALL) != (unsigned int)device) { + standby(); + } + if (device & ~(mHwDev->getSupportedDevices())) { + ALOGW("AudioStreamIn: setParameters() device(s) not supported, " + "will use default devices"); + } + else { + mDevices = device; + ALOGV("AudioStreamIn: setParameters() device set to [0x%x]", + mDevices); + } + } + + return 0; +} + +char *AudioStreamIn::getParameters(const char *keys) const +{ + ALOGV("AudioStreamIn: getParameters()"); + + return NULL; +} + +int AudioStreamIn::addAudioEffect(effect_handle_t effect) const +{ + ALOGV("AudioStreamIn: addAudioEffect()"); + + return 0; +} + +int AudioStreamIn::removeAudioEffect(effect_handle_t effect) const +{ + ALOGV("AudioStreamIn: removeAudioEffect()"); + + return 0; +} + +int AudioStreamIn::setGain(float gain) +{ + ALOGV("AudioStreamIn: setGain()"); + + return 0; +} + +ssize_t AudioStreamIn::read(void* buffer, size_t bytes) +{ + uint32_t frames = mParams.bytesToFrames(bytes); + int ret = 0; + uint32_t usecs = (frames * 1000000) / mParams.sampleRate; + + ALOGVV("AudioStreamIn: read %u frames (%u bytes) buffer %p", + frames, bytes, buffer); + + AutoMutex lock(mLock); + + if (mStandby) { + mHwDev->mMixer.setPath(mDevices, true); + ret = mReader->registerStream(mStream); + if (ret) { + ALOGE("AudioStreamIn: failed to register Dest %d", ret); + return ret; + } + ret = mStream->start(); + if (ret) { + ALOGE("AudioStreamIn: failed to start stream %d", ret); + mReader->unregisterStream(mStream); + usleep(usecs); /* limits the rate of error messages */ + return ret; + } + + mStandby = false; + } + + ret = mStream->read(buffer, frames); + if (ret < 0) { + ALOGE("AudioStreamIn: failed to read data %d", ret); + uint32_t usecs = (frames * 1000000) / mParams.sampleRate; + usleep(usecs); + bytes = ret; + } else { + ALOGW_IF(ret != (int)frames, + "AudioStreamIn: read only %d out of %d requested frames", + ret, frames); + bytes = mParams.framesToBytes(ret); + if (mHwDev->mMicMute) + memset(buffer, 0, bytes); + } + + return bytes; +} + +uint32_t AudioStreamIn::getInputFramesLost() +{ + ALOGVV("AudioStreamIn: getInputFrameLost()"); + + return 0; +} + +/* ---------------------------------------------------------------------------------------- */ + +AudioHwDevice::AudioHwDevice(uint32_t card) + : mCardId(card), mMixer(mCardId), mMicMute(false) +{ + ALOGI("AudioHwDevice: create hw device for card hw:%u", card); + + /* Mixer for dra7evm and input/output ports for JAMR3 PCM device */ + for (uint32_t i = 0; i < kNumPorts; i++) { + ALSAInPort *inPort = new ALSAInPort(mCardId, i); + mInPorts.push_back(inPort); + + ALSAOutPort *outPort = new ALSAOutPort(mCardId, i); + mOutPorts.push_back(outPort); + } + + /* PCM parameters for the port associated with on-board audio: + * 2 channels, 16-bits/sample, 44.1kHz, buffer of 882 frames (capture) */ + PcmParams params0(kCPUNumChannels, kSampleSize, kSampleRate, kCaptureFrameCount); + PcmReader *reader = new PcmReader(mInPorts[kCPUPortId], params0); + mReaders.push_back(reader); + /* 2 channels, 16-bits/sample, 44.1kHz, buffer of 1024 frames (playback) */ + params0.frameCount = kPlaybackFrameCount; + PcmWriter *writer = new PcmWriter(mOutPorts[kCPUPortId], params0); + mWriters.push_back(writer); + + /* PCM parameters for the port associated with JAMR3 audio: + * 8 channels, 16-bits/sample, 44.1kHz, buffer of 882 frames (capture) */ + PcmParams params1(kJAMR3NumChannels, kSampleSize, kSampleRate, kCaptureFrameCount); + reader = new PcmReader(mInPorts[kJAMR3PortId], params1); + mReaders.push_back(reader); + /* 8 channels, 16-bits/sample, 44.1kHz, buffer of 1024 frames (playback) */ + params1.frameCount = kPlaybackFrameCount; + writer = new PcmWriter(mOutPorts[kJAMR3PortId], params1); + mWriters.push_back(writer); + + mMixer.initRoutes(); +} + +AudioHwDevice::~AudioHwDevice() +{ + ALOGI("AudioHwDevice: destroy hw device for card hw:%u", mCardId); + + for (WriterVect::const_iterator i = mWriters.begin(); i != mWriters.end(); ++i) { + delete (*i); + } + for (ReaderVect::const_iterator i = mReaders.begin(); i != mReaders.end(); ++i) { + delete (*i); + } + for (OutPortVect::iterator i = mOutPorts.begin(); i != mOutPorts.end(); ++i) { + delete (*i); + } + for (InPortVect::iterator i = mInPorts.begin(); i != mInPorts.end(); ++i) { + delete (*i); + } +} + +uint32_t AudioHwDevice::getSupportedDevices() const +{ + uint32_t devices; + + devices = AUDIO_DEVICE_IN_BUILTIN_MIC | + AUDIO_DEVICE_IN_BACK_MIC | + AUDIO_DEVICE_IN_VOICE_CALL | + AUDIO_DEVICE_OUT_SPEAKER | + AUDIO_DEVICE_OUT_WIRED_HEADPHONE | + AUDIO_DEVICE_OUT_WIRED_HEADSET | + AUDIO_DEVICE_OUT_WIRED_HEADPHONE2; + ALOGV("AudioHwDevice: supported devices 0x%08x", devices); + + return devices; +} + +int AudioHwDevice::initCheck() const +{ + if (!mMixer.initCheck()) { + ALOGE("AudioHwDevice: ALSA mixer init failed"); + return -ENODEV; + } + + for (ReaderVect::const_iterator i = mReaders.begin(); i != mReaders.end(); ++i) { + if (!((*i)->initCheck())) { + ALOGE("AudioHwDevice: PCM reader initCheck failed"); + return -ENODEV; + } + } + for (WriterVect::const_iterator i = mWriters.begin(); i != mWriters.end(); ++i) { + if (!((*i)->initCheck())) { + ALOGE("AudioHwDevice: PCM writer init failed"); + return -ENODEV; + } + } + + return 0; +} + +int AudioHwDevice::setVoiceVolume(float volume) +{ + ALOGV("AudioHwDevice: setVoiceVolume() vol=%.4f", volume); + return -ENOSYS; +} + +int AudioHwDevice::setMasterVolume(float volume) +{ + ALOGV("AudioHwDevice: setMasterVolume() vol=%.4f", volume); + return -ENOSYS; +} + +const char *AudioHwDevice::getModeName(audio_mode_t mode) const +{ + switch (mode) { + case AUDIO_MODE_CURRENT: + return "CURRENT"; + case AUDIO_MODE_NORMAL: + return "NORMAL"; + case AUDIO_MODE_RINGTONE: + return "RINGTONE"; + case AUDIO_MODE_IN_CALL: + return "IN_CALL"; + case AUDIO_MODE_IN_COMMUNICATION: + return "COMMUNICATION"; + default: + return "INVALID"; + } +} + +int AudioHwDevice::setMode(audio_mode_t mode) +{ + ALOGV("AudioHwDevice: setMode() %s", getModeName(mode)); + + return 0; +} + +int AudioHwDevice::setMicMute(bool state) +{ + ALOGV("AudioHwDevice: setMicMute() %s", state ? "mute" : "unmute"); + + mMicMute = state; + + return 0; +} + +int AudioHwDevice::getMicMute(bool *state) const +{ + ALOGV("AudioHwDevice: getMicMute()"); + + *state = mMicMute; + + return 0; +} + +int AudioHwDevice::setParameters(const char *kv_pairs) +{ + ALOGV("AudioHwDevice: setParameters() '%s'", kv_pairs ? kv_pairs : ""); + + return 0; +} + +char *AudioHwDevice::getParameters(const char *keys) const +{ + ALOGV("AudioHwDevice: getParameters()"); + + return NULL; +} + +size_t AudioHwDevice::getInputBufferSize(const struct audio_config *config) const +{ + ALOGV("AudioHwDevice: getInputBufferSize()"); + + size_t size; + + /* Take resampling ratio into account and align to the nearest + * 16 frames as required by the AudioFlinger */ + /* Use port 0 for the calculation, since values for both ports are the same */ + uint32_t frames = mReaders[kCPUPortId]->getParams().frameCount; + uint32_t rate = mReaders[kCPUPortId]->getParams().sampleRate; + + size = (frames * config->sample_rate) / rate; + size = ((size + 15) & ~15) * mReaders[kCPUPortId]->getParams().frameSize(); + + ALOGV("AudioHwDevice: getInputBufferSize() %d bytes", size); + + return size; +} + +int AudioHwDevice::dump(int fd) const +{ + ALOGV("AudioHwDevice: dump()"); + + return 0; +} + +int AudioHwDevice::setMasterMute(bool mute) +{ + ALOGV("AudioHwDevice: setMasterMute() %s", mute ? "mute" : "unmute"); + return -ENOSYS; +} + +AudioStreamIn* AudioHwDevice::openInputStream(audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config) +{ + uint32_t port = 0; + uint32_t channels = popcount(config->channel_mask); + + ALOGV("AudioHwDevice: openInputStream()"); + + uint32_t srcMask, dstMask; + switch (devices) { + case AUDIO_DEVICE_IN_BUILTIN_MIC: + case AUDIO_DEVICE_IN_VOICE_CALL: + if (channels == 1) { + /* Mic is in slots 0&1 (mask = 0x03) on port 0, but AF wants + * only mono so take only one channel here */ + srcMask = 0x01; + dstMask = 0x01; + } + else { + srcMask = 0x03; + dstMask = 0x03; + } + port = 0; + break; + case AUDIO_DEVICE_IN_BACK_MIC: + if (channels == 1) { + srcMask = 0x08; + dstMask = 0x01; + } + else { + ALOGE("AudioHwDevice: device 0x%08x only supports 1 channel", + devices); + return NULL; + } + port = 1; + break; + default: + ALOGE("AudioHwDevice: device 0x%08x is not supported", devices); + return NULL; + } + + SlotMap slotMap(srcMask, dstMask); + + /* Set the parameters for the internal input stream. Don't change the + * parameters for capture. The resampler is used if needed. */ + PcmParams params(*config, mReaders[port]->getParams().frameCount); + + sp in = new AudioStreamIn(this, mReaders[port], params, + slotMap, devices); + if ((in == NULL) || in->initCheck()) { + ALOGE("AudioHwDevice: failed to open input stream on port hw:%u,%u", + mCardId, port); + return NULL; + } + + mInStreams.insert(in); + + return in.get(); +} + +void AudioHwDevice::closeInputStream(AudioStreamIn *in) +{ + ALOGV("AudioHwDevice: closeInputStream()"); + + if (mInStreams.find(in) == mInStreams.end()) { + ALOGW("AudioHwDevice: input stream %p is not open", in); + return; + } + + mInStreams.erase(in); + + in = NULL; +} + +AudioStreamOut* AudioHwDevice::openOutputStream(audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config) +{ + uint32_t port = 0; + PcmParams params; + + ALOGV("AudioHwDevice: openOutputStream()"); + + uint32_t destMask; + switch (devices) { + case AUDIO_DEVICE_OUT_SPEAKER: + port = 0; + destMask = 0x03; + break; + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE: + case AUDIO_DEVICE_OUT_WIRED_HEADSET: + port = 1; + destMask = 0x0c; + break; + case AUDIO_DEVICE_OUT_WIRED_HEADPHONE2: + port = 1; + destMask = 0x30; + break; + default: + ALOGE("AudioHwDevice: device 0x%08x is not supported", devices); + return NULL; + } + + SlotMap slotMap(0x03, destMask); + if (!slotMap.isValid()) { + ALOGE("AudioHwDevice: failed to create slot map"); + return NULL; + } + + /* Set the parameters for the internal output stream */ + params.frameCount = mWriters[port]->getParams().frameCount; + params.sampleRate = config->sample_rate; /* Use stream's resampler if needed */ + params.sampleBits = 16; /* 16-bits/sample */ + params.channels = 2; /* Listening zones are stereo */ + + /* Update audio config with granted parameters */ + if (popcount(config->channel_mask) != (int)params.channels) { + ALOGV("AudioHwDevice: updating audio config channel mask [0x%x]->[0x%x]", + config->channel_mask, + audio_channel_out_mask_from_count(params.channels)); + } + config->channel_mask = audio_channel_out_mask_from_count(params.channels); + if (config->format != AUDIO_FORMAT_PCM_16_BIT) { + ALOGV("AudioHwDevice: updating audio config format [0x%x]->[0x%x]", + config->format, AUDIO_FORMAT_PCM_16_BIT); + } + config->format = AUDIO_FORMAT_PCM_16_BIT; + + sp out = new AudioStreamOut(this, mWriters[port], params, + slotMap, devices); + if ((out == NULL) || out->initCheck()) { + ALOGE("AudioHwDevice: failed to open output stream on port hw:%u,%u", + mCardId, port); + return NULL; + } + + mOutStreams.insert(out); + + return out.get(); +} + +void AudioHwDevice::closeOutputStream(AudioStreamOut *out) +{ + ALOGV("AudioHwDevice: closeOutputStream()"); + + if (mOutStreams.find(out) == mOutStreams.end()) { + ALOGW("AudioHwDevice: output stream %p is not open", out); + return; + } + + mOutStreams.erase(out); + + out = NULL; +} + +}; /* namespace android */ diff --git a/audio/multizone/AudioHw.h b/audio/multizone/AudioHw.h new file mode 100644 index 0000000..2a5e296 --- /dev/null +++ b/audio/multizone/AudioHw.h @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2013 Texas Instruments + * + * 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. + */ + +#ifndef _AUDIO_HW_H_ +#define _AUDIO_HW_H_ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace android { + +using namespace tiaudioutils; +using std::vector; + +class AudioHwDevice; + +class AudioStream { + public: + virtual ~AudioStream() {} + virtual uint32_t getSampleRate() const = 0; + virtual int setSampleRate(uint32_t rate) = 0; + virtual size_t getBufferSize() const = 0; + virtual audio_channel_mask_t getChannels() const = 0; + virtual audio_format_t getFormat() const = 0; + virtual int setFormat(audio_format_t format) = 0; + virtual int standby() = 0; + virtual int dump(int fd) const = 0; + virtual audio_devices_t getDevice() const = 0; + virtual int setDevice(audio_devices_t device) { return 0; } /* unused */ + virtual int setParameters(const char *kv_pairs) = 0; + virtual char *getParameters(const char *keys) const = 0; + virtual int addAudioEffect(effect_handle_t effect) const = 0; + virtual int removeAudioEffect(effect_handle_t effect) const = 0; + + // FIXME not used + static const uint32_t kDefaultSampleRate = 44100; + static const uint32_t kDefaultBufferSize = 4096; +}; + +class AudioStreamOut : public RefBase, public AudioStream { + public: + AudioStreamOut(AudioHwDevice *hwDev, + PcmWriter *writer, + const PcmParams ¶ms, + const SlotMap &map, + audio_devices_t devices); + virtual ~AudioStreamOut() {}; + int initCheck() const; + + /* From AudioStream */ + virtual uint32_t getSampleRate() const; + virtual int setSampleRate(uint32_t rate); + virtual size_t getBufferSize() const; + virtual audio_channel_mask_t getChannels() const; + virtual audio_format_t getFormat() const; + virtual int setFormat(audio_format_t format); + virtual int standby(); + virtual int dump(int fd) const; + virtual audio_devices_t getDevice() const; + virtual int setParameters(const char *kv_pairs); + virtual char *getParameters(const char *keys) const; + virtual int addAudioEffect(effect_handle_t effect) const; + virtual int removeAudioEffect(effect_handle_t effect) const; + + /* AudioStreamOut specific */ + uint32_t getLatency() const; + int setVolume(float left, float right); + ssize_t write(const void* buffer, size_t bytes); + int getRenderPosition(uint32_t *dsp_frames) const; + int getNextWriteTimestamp(int64_t *timestamp) const; + + protected: + AudioHwDevice *mHwDev; + PcmWriter *mWriter; + PcmParams mParams; + audio_devices_t mDevices; + sp mStream; + bool mStandby; + Mutex mLock; +}; + +class AudioStreamIn : public RefBase, public AudioStream { + public: + AudioStreamIn(AudioHwDevice *hwDev, + PcmReader *reader, + const PcmParams ¶ms, + const SlotMap &map, + audio_devices_t devices); + virtual ~AudioStreamIn() {}; + int initCheck() const; + + /* From AudioStream */ + virtual uint32_t getSampleRate() const; + virtual int setSampleRate(uint32_t rate); + virtual size_t getBufferSize() const; + virtual audio_channel_mask_t getChannels() const; + virtual audio_format_t getFormat() const; + virtual int setFormat(audio_format_t format); + virtual int standby(); + virtual int dump(int fd) const; + virtual audio_devices_t getDevice() const; + virtual int setParameters(const char *kv_pairs); + virtual char *getParameters(const char *keys) const; + virtual int addAudioEffect(effect_handle_t effect) const; + virtual int removeAudioEffect(effect_handle_t effect) const; + + /* AudioStreamIn specific */ + int setGain(float gain); + ssize_t read(void* buffer, size_t bytes); + uint32_t getInputFramesLost(); + + protected: + AudioHwDevice *mHwDev; + PcmReader *mReader; + PcmParams mParams; + audio_devices_t mDevices; + audio_source_t mSource; + sp mStream; + bool mStandby; + Mutex mLock; +}; + +class AudioHwDevice { + public: + AudioHwDevice(uint32_t card); + virtual ~AudioHwDevice(); + + uint32_t getSupportedDevices() const; + int initCheck() const; + int setVoiceVolume(float volume); + int setMasterVolume(float volume); + int setMode(audio_mode_t mode); + int setMicMute(bool state); + int getMicMute(bool *state) const; + int setParameters(const char *kv_pairs); + char *getParameters(const char *keys) const; + size_t getInputBufferSize(const struct audio_config *config) const; + int dump(int fd) const; + int setMasterMute(bool mute); + AudioStreamIn* openInputStream(audio_io_handle_t handle, + audio_devices_t devices, + struct audio_config *config); + void closeInputStream(AudioStreamIn *in); + AudioStreamOut* openOutputStream(audio_io_handle_t handle, + audio_devices_t devices, + audio_output_flags_t flags, + struct audio_config *config); + void closeOutputStream(AudioStreamOut *out); + + friend class AudioStreamIn; + friend class AudioStreamOut; + + static const uint32_t kNumPorts = 2; + static const uint32_t kCPUPortId = 0; + static const uint32_t kJAMR3PortId = 1; + static const uint32_t kCPUNumChannels = 2; + static const uint32_t kJAMR3NumChannels = 8; + + static const uint32_t kSampleRate = 44100; + static const uint32_t kSampleSize = 16; + static const uint32_t kCaptureFrameCount = 882; + static const uint32_t kPlaybackFrameCount = 1024; + + protected: + typedef set< sp > StreamInSet; + typedef set< sp > StreamOutSet; + typedef vector InPortVect; + typedef vector OutPortVect; + typedef vector ReaderVect; + typedef vector WriterVect; + + const char *getModeName(audio_mode_t mode) const; + + uint32_t mCardId; + ALSAMixer mMixer; + InPortVect mInPorts; + OutPortVect mOutPorts; + ReaderVect mReaders; + WriterVect mWriters; + StreamInSet mInStreams; + StreamOutSet mOutStreams; + bool mMicMute; +}; + +}; // namespace android + +#endif /* _AUDIO_HW_H_ */ diff --git a/audio/multizone/audio_hw.cpp b/audio/multizone/audio_hw.cpp new file mode 100644 index 0000000..3e429c4 --- /dev/null +++ b/audio/multizone/audio_hw.cpp @@ -0,0 +1,562 @@ +/* + * Copyright (C) 2013 Texas Instruments + * + * 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_primary" +/* #define LOG_NDEBUG 0 */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +extern "C" { + +namespace android { + +struct mz_audio_device { + struct audio_hw_device device; + AudioHwDevice *hwDev; +}; + +struct mz_stream_in { + struct audio_stream_in stream; + AudioStreamIn *streamIn; +}; + +struct mz_stream_out { + struct audio_stream_out stream; + AudioStreamOut *streamOut; +}; + +static inline AudioHwDevice *toAudioHwDev(struct audio_hw_device *dev) +{ + return reinterpret_cast(dev)->hwDev; +} + +static inline const AudioHwDevice *tocAudioHwDev(const struct audio_hw_device *dev) +{ + return reinterpret_cast(dev)->hwDev; +} + +static inline AudioStreamIn *toStreamIn(struct audio_stream_in *in) +{ + return reinterpret_cast(in)->streamIn; +} + +static inline const AudioStreamIn *tocStreamIn(const struct audio_stream_in *in) +{ + return reinterpret_cast(in)->streamIn; +} + +static inline AudioStreamOut *toStreamOut(struct audio_stream_out *out) +{ + return reinterpret_cast(out)->streamOut; +} + +static inline const AudioStreamOut *tocStreamOut(const struct audio_stream_out *out) +{ + return reinterpret_cast(out)->streamOut; +} + +/* audio HAL functions */ + +/* audio_stream_out implementation */ + +static uint32_t out_get_sample_rate(const struct audio_stream *stream) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->getSampleRate(); +} + +static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + AudioStreamOut *out = toStreamOut((audio_stream_out *)stream); + return out->setSampleRate(rate); +} + +static size_t out_get_buffer_size(const struct audio_stream *stream) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->getBufferSize(); +} + +static audio_channel_mask_t out_get_channels(const struct audio_stream *stream) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->getChannels(); +} + +static audio_format_t out_get_format(const struct audio_stream *stream) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->getFormat(); +} + +static int out_set_format(struct audio_stream *stream, audio_format_t format) +{ + AudioStreamOut *out = toStreamOut((audio_stream_out *)stream); + return out->setFormat(format); +} + +static int out_standby(struct audio_stream *stream) +{ + AudioStreamOut *out = toStreamOut((audio_stream_out *)stream); + return out->standby(); +} + +static int out_dump(const struct audio_stream *stream, int fd) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->dump(fd); +} + +static int out_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + AudioStreamOut *out = toStreamOut((audio_stream_out *)stream); + return out->setParameters(kvpairs); +} + +static char* out_get_parameters(const struct audio_stream *stream, const char *keys) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->getParameters(keys); +} + +static uint32_t out_get_latency(const struct audio_stream_out *stream) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->getLatency(); +} + +static int out_set_volume(struct audio_stream_out *stream, float left, + float right) +{ + AudioStreamOut *out = toStreamOut((audio_stream_out *)stream); + return out->setVolume(left, right); +} + +static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, + size_t bytes) +{ + AudioStreamOut *out = toStreamOut((audio_stream_out *)stream); + return out->write(buffer, bytes); +} + +static int out_get_render_position(const struct audio_stream_out *stream, + uint32_t *dsp_frames) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->getRenderPosition(dsp_frames); +} + +static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->addAudioEffect(effect); +} + +static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->removeAudioEffect(effect); +} + +static int out_get_next_write_timestamp(const struct audio_stream_out *stream, + int64_t *timestamp) +{ + const AudioStreamOut *out = tocStreamOut((audio_stream_out *)stream); + return out->getNextWriteTimestamp(timestamp); +} + +/* audio_stream_in implementation */ + +static uint32_t in_get_sample_rate(const struct audio_stream *stream) +{ + const AudioStreamIn *in = tocStreamIn((audio_stream_in *)stream); + return in->getSampleRate(); +} + +static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate) +{ + AudioStreamIn *in = toStreamIn((audio_stream_in *)stream); + return in->setSampleRate(rate); +} + +static size_t in_get_buffer_size(const struct audio_stream *stream) +{ + const AudioStreamIn *in = tocStreamIn((audio_stream_in *)stream); + return in->getBufferSize(); +} + +static audio_channel_mask_t in_get_channels(const struct audio_stream *stream) +{ + const AudioStreamIn *in = tocStreamIn((audio_stream_in *)stream); + return in->getChannels(); +} + +static audio_format_t in_get_format(const struct audio_stream *stream) +{ + const AudioStreamIn *in = tocStreamIn((audio_stream_in *)stream); + return in->getFormat(); +} + +static int in_set_format(struct audio_stream *stream, audio_format_t format) +{ + AudioStreamIn *in = toStreamIn((audio_stream_in *)stream); + return in->setFormat(format); +} + +static int in_standby(struct audio_stream *stream) +{ + AudioStreamIn *in = toStreamIn((audio_stream_in *)stream); + return in->standby(); +} + +static int in_dump(const struct audio_stream *stream, int fd) +{ + const AudioStreamIn *in = tocStreamIn((audio_stream_in *)stream); + return in->dump(fd); +} + +static int in_set_parameters(struct audio_stream *stream, const char *kvpairs) +{ + AudioStreamIn *in = toStreamIn((audio_stream_in *)stream); + return in->setParameters(kvpairs); +} + +static char * in_get_parameters(const struct audio_stream *stream, + const char *keys) +{ + const AudioStreamIn *in = tocStreamIn((audio_stream_in *)stream); + return in->getParameters(keys); +} + +static int in_set_gain(struct audio_stream_in *stream, float gain) +{ + AudioStreamIn *in = toStreamIn(stream); + return in->setGain(gain); +} + +static ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes) +{ + AudioStreamIn *in = toStreamIn(stream); + return in->read(buffer, bytes); +} + +static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream) +{ + AudioStreamIn *in = toStreamIn(stream); + return in->getInputFramesLost(); +} + +static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + const AudioStreamIn *in = tocStreamIn((audio_stream_in *)stream); + return in->addAudioEffect(effect); +} + +static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect) +{ + const AudioStreamIn *in = tocStreamIn((audio_stream_in *)stream); + return in->removeAudioEffect(effect); +} + +/* audio_hw_device implementation */ + +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) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + struct mz_stream_out *out; + + out = (struct mz_stream_out *)malloc(sizeof(*out)); + if (!out) + return -ENOMEM; + + ALOGV("adev_open_output_stream() stream %p, %u Hz, %u channels, " + "%u bits/sample, flags 0x%08x", + out, config->sample_rate, popcount(config->channel_mask), + audio_bytes_per_sample(config->format) * 8, flags); + + 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->streamOut = hwDev->openOutputStream(handle, devices, flags, config); + if (!out->streamOut) { + ALOGE("adev_open_output_stream() failed to open stream"); + free(out); + return -ENODEV; + } + + *stream_out = &out->stream; + + return 0; +} + +static void adev_close_output_stream(struct audio_hw_device *dev, + struct audio_stream_out *stream) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + AudioStreamOut *out = toStreamOut(stream); + + ALOGV("adev_close_output_stream() stream %p", stream); + + out_standby(&stream->common); + + /* closeOutputStream() also deletes the out object */ + hwDev->closeOutputStream(out); + + free(stream); +} + +static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + return hwDev->setParameters(kvpairs); +} + +static char *adev_get_parameters(const struct audio_hw_device *dev, + const char *keys) +{ + const AudioHwDevice *hwDev = tocAudioHwDev(dev); + return hwDev->getParameters(keys); +} + +static int adev_init_check(const struct audio_hw_device *dev) +{ + const AudioHwDevice *hwDev = tocAudioHwDev(dev); + return hwDev->initCheck(); +} + +static int adev_set_voice_volume(struct audio_hw_device *dev, float volume) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + return hwDev->setVoiceVolume(volume); +} + +static int adev_set_master_volume(struct audio_hw_device *dev, float volume) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + return hwDev->setMasterVolume(volume); +} + +static int adev_set_master_mute(struct audio_hw_device *dev, bool muted) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + return hwDev->setMasterMute(muted); +} + +static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + return hwDev->setMode(mode); +} + +static int adev_set_mic_mute(struct audio_hw_device *dev, bool state) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + return hwDev->setMicMute(state); +} + +static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state) +{ + const AudioHwDevice *hwDev = tocAudioHwDev(dev); + return hwDev->getMicMute(state); +} + +static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev, + const struct audio_config *config) +{ + const AudioHwDevice *hwDev = tocAudioHwDev(dev); + return hwDev->getInputBufferSize(config); +} + +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) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + struct mz_stream_in *in; + int ret; + + in = (struct mz_stream_in *)malloc(sizeof(*in)); + if (!in) + return -ENOMEM; + + ALOGV("adev_open_input_stream() stream %p, %u Hz, %u channels, " + "%u bits/sample", + in, config->sample_rate, popcount(config->channel_mask), + audio_bytes_per_sample(config->format) * 8); + + 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->streamIn = hwDev->openInputStream(handle, devices, config); + if (!in->streamIn) { + ALOGE("adev_open_input_stream() failed to open stream"); + free(in); + return -ENODEV; + } + + *stream_in = &in->stream; + + return 0; +} + +static void adev_close_input_stream(struct audio_hw_device *dev, + struct audio_stream_in *stream) +{ + AudioHwDevice *hwDev = toAudioHwDev(dev); + AudioStreamIn *in = toStreamIn(stream); + + ALOGV("adev_close_input_stream() stream %p", stream); + + in_standby(&stream->common); + + /* closeInputStream() also deletes the in object */ + hwDev->closeInputStream(in); + + free(stream); +} + +static int adev_dump(const audio_hw_device_t *device, int fd) +{ + return 0; +} + +static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev) +{ + const AudioHwDevice *hwDev = tocAudioHwDev(dev); + return hwDev->getSupportedDevices(); +} + +static int adev_close(hw_device_t *device) +{ + ALOGI("adev_close()"); + + free(device); + + return 0; +} + +static int adev_open(const hw_module_t* module, const char* name, hw_device_t** device) +{ + struct mz_audio_device *adev; + + ALOGI("adev_open() %s", name); + + if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) + return -EINVAL; + + adev = (struct mz_audio_device*)calloc(1, sizeof(*adev)); + if (!adev) + return -ENOMEM; + + 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.get_supported_devices = adev_get_supported_devices; + 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.set_master_mute = adev_set_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; + + adev->hwDev = new AudioHwDevice(0); + + *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 */ "Jacinto6 Multizone Audio HAL", + /* author */ "Texas Instruments Inc.", + /* methods */ &hal_module_methods, + /* dso */ NULL, + /* reserved */ {0}, + }, +}; + +} /* namespace android */ + +} /* extern "C" */ diff --git a/audio/multizone/audio_policy.conf b/audio/multizone/audio_policy.conf new file mode 100644 index 0000000..2f4eb19 --- /dev/null +++ b/audio/multizone/audio_policy.conf @@ -0,0 +1,116 @@ +# Global configuration section: lists input and output devices always present on the device +# as well as the output device selected by default. +# Devices are designated by a string that corresponds to the enum in audio.h + +global_configuration { + attached_output_devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_WIRED_HEADPHONE2 + default_output_device AUDIO_DEVICE_OUT_SPEAKER + attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC +} + +# Zone affinity section: lists the output devices allowed per listening zone. Devices are +# designated by a string that corresponds to the enum in audio.h. Multiple devices can be +# concatenated by use of "|" without space or "\n". + +zone_affinity { + CABIN AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_ALL_A2DP|AUDIO_DEVICE_IN_REMOTE_SUBMIX + BACKSEAT1 AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_ALL_A2DP|AUDIO_DEVICE_IN_REMOTE_SUBMIX + BACKSEAT2 AUDIO_DEVICE_OUT_WIRED_HEADPHONE2|AUDIO_DEVICE_OUT_ALL_A2DP|AUDIO_DEVICE_IN_REMOTE_SUBMIX +} + +# audio hardware module section: contains descriptors for all audio hw modules present on the +# device. Each hw module node is named after the corresponding hw module library base name. +# For instance, "primary" corresponds to audio.primary..so. +# The "primary" module is mandatory and must include at least one output with +# AUDIO_OUTPUT_FLAG_PRIMARY flag. +# Each module descriptor contains one or more output profile descriptors and zero or more +# input profile descriptors. Each profile lists all the parameters supported by a given output +# or input stream category. +# The "channel_masks", "formats", "devices" and "flags" are specified using strings corresponding +# to enums in audio.h and audio_policy.h. They are concatenated by use of "|" without space or "\n". + +audio_hw_modules { + primary { + outputs { + primary { + sampling_rates 44100 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_SPEAKER + flags AUDIO_OUTPUT_FLAG_PRIMARY + } + hp1 { + sampling_rates 44100 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE + } + hp2 { + sampling_rates 44100 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_WIRED_HEADPHONE2 + } + } + inputs { + primary { + sampling_rates 8000|11025|16000|22050|32000|44100|48000 + channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_BACK_MIC|AUDIO_DEVICE_IN_VOICE_CALL + } + } + } + hdmi { + outputs { + stereo { + sampling_rates 44100|48000 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_AUX_DIGITAL + } + multichannel { + sampling_rates 44100|48000 + channel_masks dynamic + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_AUX_DIGITAL + flags AUDIO_OUTPUT_FLAG_DIRECT + } + } + } + a2dp { + outputs { + a2dp { + sampling_rates 44100 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_ALL_A2DP + } + } + } + r_submix { + outputs { + r_submix { + sampling_rates 44100|48000 + channel_masks AUDIO_CHANNEL_OUT_STEREO + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX + } + multichannel { + sampling_rates 44100|48000 + channel_masks AUDIO_CHANNEL_OUT_5POINT1 + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_OUT_REMOTE_SUBMIX + flags AUDIO_OUTPUT_FLAG_DIRECT + } + } + inputs { + r_submix { + sampling_rates 44100|48000 + channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO|AUDIO_CHANNEL_IN_5POINT1EMUL + formats AUDIO_FORMAT_PCM_16_BIT + devices AUDIO_DEVICE_IN_REMOTE_SUBMIX + } + } + } +} diff --git a/audio/multizone/dra7evm_paths.xml b/audio/multizone/dra7evm_paths.xml new file mode 100644 index 0000000..a64ea4c --- /dev/null +++ b/audio/multizone/dra7evm_paths.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3-54-g00ecf