diff options
-rw-r--r-- | include/media/IOMX.h | 2 | ||||
-rw-r--r-- | include/ndk/NdkMediaCodec.h | 14 | ||||
-rw-r--r-- | include/ndk/NdkMediaFormat.h | 22 | ||||
-rw-r--r-- | include/ndk/NdkMediaMuxer.h | 75 | ||||
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 4 | ||||
-rw-r--r-- | media/libstagefright/ACodec.cpp | 22 | ||||
-rw-r--r-- | media/libstagefright/OMXCodec.cpp | 38 | ||||
-rw-r--r-- | media/libstagefright/omx/OMX.cpp | 2 | ||||
-rw-r--r-- | media/ndk/Android.mk | 1 | ||||
-rw-r--r-- | media/ndk/NdkMediaCodec.cpp | 13 | ||||
-rw-r--r-- | media/ndk/NdkMediaFormat.cpp | 58 | ||||
-rw-r--r-- | media/ndk/NdkMediaFormatPriv.h | 2 | ||||
-rw-r--r-- | media/ndk/NdkMediaMuxer.cpp | 99 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 12 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 11 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.cpp | 460 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyManager.h | 9 | ||||
-rw-r--r-- | services/audiopolicy/AudioPolicyService.cpp | 4 |
18 files changed, 649 insertions, 199 deletions
diff --git a/include/media/IOMX.h b/include/media/IOMX.h index f6f9e7a..176f72d 100644 --- a/include/media/IOMX.h +++ b/include/media/IOMX.h @@ -184,8 +184,6 @@ struct omx_message { OMX_U32 range_length; OMX_U32 flags; OMX_TICKS timestamp; - OMX_PTR platform_private; - OMX_PTR data_ptr; } extended_buffer_data; } u; diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h index 5067073..2af88d0 100644 --- a/include/ndk/NdkMediaCodec.h +++ b/include/ndk/NdkMediaCodec.h @@ -49,6 +49,7 @@ typedef struct AMediaCodecBufferInfo AMediaCodecBufferInfo; enum { AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM = 4, + AMEDIACODEC_CONFIGURE_FLAG_ENCODE = 1, AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED = -3, AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED = -2, AMEDIACODEC_INFO_TRY_AGAIN_LATER = -1 @@ -56,20 +57,22 @@ enum { /** - * Create decoder by name. Use this if you know the exact codec you want to use. + * Create codec by name. Use this if you know the exact codec you want to use. + * When configuring, you will need to specify whether to use the codec as an + * encoder or decoder. */ -AMediaCodec* AMediaCodec_createByCodecName(const char *name); +AMediaCodec* AMediaCodec_createCodecByName(const char *name); /** * Create codec by mime type. Most applications will use this, specifying a * mime type obtained from media extractor. */ -AMediaCodec* AMediaCodec_createByCodecType(const char *mime_type); +AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type); /** * Create encoder by name. */ -AMediaCodec* AMediaCodec_createEncoderByName(const char *name); +AMediaCodec* AMediaCodec_createEncoderByType(const char *mime_type); /** * delete the codec and free its resources @@ -79,7 +82,8 @@ int AMediaCodec_delete(AMediaCodec*); /** * Configure the codec. For decoding you would typically get the format from an extractor. */ -int AMediaCodec_configure(AMediaCodec*, AMediaFormat *format, ANativeWindow* surface); // TODO: other args +int AMediaCodec_configure(AMediaCodec*, const AMediaFormat* format, + ANativeWindow* surface, uint32_t flags); // TODO: other args /** * Start the codec. A codec must be configured before it can be started, and must be started diff --git a/include/ndk/NdkMediaFormat.h b/include/ndk/NdkMediaFormat.h index 4489b78..e0caeab 100644 --- a/include/ndk/NdkMediaFormat.h +++ b/include/ndk/NdkMediaFormat.h @@ -48,14 +48,32 @@ const char* AMediaFormat_toString(AMediaFormat*); bool AMediaFormat_getInt32(AMediaFormat*, const char *name, int32_t *out); bool AMediaFormat_getInt64(AMediaFormat*, const char *name, int64_t *out); bool AMediaFormat_getFloat(AMediaFormat*, const char *name, float *out); -bool AMediaFormat_getDouble(AMediaFormat*, const char *name, double *out); -bool AMediaFormat_getSize(AMediaFormat*, const char *name, size_t *out); +/** + * The returned data is owned by the format and remains valid as long as the named entry + * is part of the format. + */ +bool AMediaFormat_getBuffer(AMediaFormat*, const char *name, void** data, size_t *size); /** * The returned string is owned by the format, and remains valid until the next call to getString, * or until the format is deleted. */ bool AMediaFormat_getString(AMediaFormat*, const char *name, const char **out); + +void AMediaFormat_setInt32(AMediaFormat*, const char* name, int32_t value); +void AMediaFormat_setInt64(AMediaFormat*, const char* name, int64_t value); +void AMediaFormat_setFloat(AMediaFormat*, const char* name, float value); +/** + * The provided string is copied into the format. + */ +void AMediaFormat_setString(AMediaFormat*, const char* name, const char* value); +/** + * The provided data is copied into the format. + */ +void AMediaFormat_setBuffer(AMediaFormat*, const char* name, void* data, size_t size); + + + /** * XXX should these be ints/enums that we look up in a table as needed? */ diff --git a/include/ndk/NdkMediaMuxer.h b/include/ndk/NdkMediaMuxer.h new file mode 100644 index 0000000..deb150d --- /dev/null +++ b/include/ndk/NdkMediaMuxer.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 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. + */ + + +/* + * This file defines an NDK API. + * Do not remove methods. + * Do not change method signatures. + * Do not change the value of constants. + * Do not change the size of any of the classes defined in here. + * Do not reference types that are not part of the NDK. + * Do not #include files that aren't part of the NDK. + */ + +#ifndef _NDK_MEDIA_MUXER_H +#define _NDK_MEDIA_MUXER_H + +#include <sys/types.h> + +#include "NdkMediaFormat.h" +#include "NdkMediaCodec.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct AMediaMuxer; +typedef struct AMediaMuxer AMediaMuxer; + +typedef enum { + AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4 = 0, + AMEDIAMUXER_OUTPUT_FORMAT_WEBM = 1, +} OutputFormat; + +/** + * Create new media muxer + */ +AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format); + +/** + * Delete a previously created media muxer + */ +int AMediaMuxer_delete(AMediaMuxer*); + +int AMediaMuxer_setLocation(AMediaMuxer*, float latitude, float longtitude); + +int AMediaMuxer_setOrientationHint(AMediaMuxer*, int degrees); + +ssize_t AMediaMuxer_addTrack(AMediaMuxer*, const AMediaFormat* format); + +int AMediaMuxer_start(AMediaMuxer*); + +int AMediaMuxer_stop(AMediaMuxer*); + +int AMediaMuxer_writeSampleData(AMediaMuxer *muxer, + size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _NDK_MEDIA_MUXER_H diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index a7bf380..2c8605c 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -79,14 +79,14 @@ AudioRecord::AudioRecord( uint32_t notificationFrames, int sessionId, transfer_type transferType, - audio_input_flags_t flags __unused) + audio_input_flags_t flags) : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mProxy(NULL) { mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user, - notificationFrames, false /*threadCanCallJava*/, sessionId, transferType); + notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags); } AudioRecord::~AudioRecord() diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 5bca317..537d9de 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -100,12 +100,6 @@ struct CodecObserver : public BnOMXObserver { msg->setInt64( "timestamp", omx_msg.u.extended_buffer_data.timestamp); - msg->setPointer( - "platform_private", - omx_msg.u.extended_buffer_data.platform_private); - msg->setPointer( - "data_ptr", - omx_msg.u.extended_buffer_data.data_ptr); break; } @@ -160,9 +154,7 @@ private: IOMX::buffer_id bufferID, size_t rangeOffset, size_t rangeLength, OMX_U32 flags, - int64_t timeUs, - void *platformPrivate, - void *dataPtr); + int64_t timeUs); void getMoreInputDataIfPossible(); @@ -3228,23 +3220,17 @@ bool ACodec::BaseState::onOMXMessage(const sp<AMessage> &msg) { int32_t rangeOffset, rangeLength, flags; int64_t timeUs; - void *platformPrivate; - void *dataPtr; CHECK(msg->findInt32("range_offset", &rangeOffset)); CHECK(msg->findInt32("range_length", &rangeLength)); CHECK(msg->findInt32("flags", &flags)); CHECK(msg->findInt64("timestamp", &timeUs)); - CHECK(msg->findPointer("platform_private", &platformPrivate)); - CHECK(msg->findPointer("data_ptr", &dataPtr)); return onOMXFillBufferDone( bufferID, (size_t)rangeOffset, (size_t)rangeLength, (OMX_U32)flags, - timeUs, - platformPrivate, - dataPtr); + timeUs); } default: @@ -3543,9 +3529,7 @@ bool ACodec::BaseState::onOMXFillBufferDone( IOMX::buffer_id bufferID, size_t rangeOffset, size_t rangeLength, OMX_U32 flags, - int64_t timeUs, - void * /* platformPrivate */, - void * /* dataPtr */) { + int64_t timeUs) { ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx", mCodec->mComponentName.c_str(), bufferID, timeUs, flags); diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index a879656..9a7f3db 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -1627,15 +1627,15 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { info.mMediaBuffer = NULL; if (portIndex == kPortIndexOutput) { - if (!(mOMXLivesLocally - && (mQuirks & kRequiresAllocateBufferOnOutputPorts) - && (mQuirks & kDefersOutputBufferAllocation))) { - // If the node does not fill in the buffer ptr at this time, - // we will defer creating the MediaBuffer until receiving - // the first FILL_BUFFER_DONE notification instead. - info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize); - info.mMediaBuffer->setObserver(this); - } + // Fail deferred MediaBuffer creation until FILL_BUFFER_DONE; + // this legacy mode is no longer supported. + LOG_ALWAYS_FATAL_IF((mOMXLivesLocally + && (mQuirks & kRequiresAllocateBufferOnOutputPorts) + && (mQuirks & kDefersOutputBufferAllocation)), + "allocateBuffersOnPort cannot defer buffer allocation"); + + info.mMediaBuffer = new MediaBuffer(info.mData, info.mSize); + info.mMediaBuffer->setObserver(this); } mPortBuffers[portIndex].push(info); @@ -2234,22 +2234,6 @@ void OMXCodec::on_message(const omx_message &msg) { } else if (mPortStatus[kPortIndexOutput] != SHUTTING_DOWN) { CHECK_EQ((int)mPortStatus[kPortIndexOutput], (int)ENABLED); - if (info->mMediaBuffer == NULL) { - CHECK(mOMXLivesLocally); - CHECK(mQuirks & kRequiresAllocateBufferOnOutputPorts); - CHECK(mQuirks & kDefersOutputBufferAllocation); - - // The qcom video decoders on Nexus don't actually allocate - // output buffer memory on a call to OMX_AllocateBuffer - // the "pBuffer" member of the OMX_BUFFERHEADERTYPE - // structure is only filled in later. - - info->mMediaBuffer = new MediaBuffer( - msg.u.extended_buffer_data.data_ptr, - info->mSize); - info->mMediaBuffer->setObserver(this); - } - MediaBuffer *buffer = info->mMediaBuffer; bool isGraphicBuffer = buffer->graphicBuffer() != NULL; @@ -2285,10 +2269,6 @@ void OMXCodec::on_message(const omx_message &msg) { } buffer->meta_data()->setPointer( - kKeyPlatformPrivate, - msg.u.extended_buffer_data.platform_private); - - buffer->meta_data()->setPointer( kKeyBufferID, msg.u.extended_buffer_data.buffer); diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp index 74076c6..b62d5f5 100644 --- a/media/libstagefright/omx/OMX.cpp +++ b/media/libstagefright/omx/OMX.cpp @@ -470,8 +470,6 @@ OMX_ERRORTYPE OMX::OnFillBufferDone( msg.u.extended_buffer_data.range_length = pBuffer->nFilledLen; msg.u.extended_buffer_data.flags = pBuffer->nFlags; msg.u.extended_buffer_data.timestamp = pBuffer->nTimeStamp; - msg.u.extended_buffer_data.platform_private = pBuffer->pPlatformPrivate; - msg.u.extended_buffer_data.data_ptr = pBuffer->pBuffer; findDispatcher(node)->post(msg); diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk index 82fb970..b8dd19e 100644 --- a/media/ndk/Android.mk +++ b/media/ndk/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES:= \ NdkMediaCodec.cpp \ NdkMediaExtractor.cpp \ NdkMediaFormat.cpp \ + NdkMediaMuxer.cpp \ LOCAL_MODULE:= libmediandk diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 5412b9b..9592af8 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -88,16 +88,16 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool } -AMediaCodec* AMediaCodec_createByCodecName(const char *name) { +AMediaCodec* AMediaCodec_createCodecByName(const char *name) { return createAMediaCodec(name, false, false); } -AMediaCodec* AMediaCodec_createByCodecType(const char *mime_type) { +AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) { return createAMediaCodec(mime_type, true, false); } -AMediaCodec* AMediaCodec_createEncoderByName(const char *name) { - return createAMediaCodec(name, false, true); +AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { + return createAMediaCodec(name, true, true); } int AMediaCodec_delete(AMediaCodec *mData) { @@ -115,7 +115,8 @@ int AMediaCodec_delete(AMediaCodec *mData) { return OK; } -int AMediaCodec_configure(AMediaCodec *mData, AMediaFormat *format, ANativeWindow* window) { +int AMediaCodec_configure( + AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, uint32_t flags) { sp<AMessage> nativeFormat; AMediaFormat_getFormat(format, &nativeFormat); ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); @@ -124,7 +125,7 @@ int AMediaCodec_configure(AMediaCodec *mData, AMediaFormat *format, ANativeWindo surface = (Surface*) window; } - return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, 0)); + return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, flags)); } int AMediaCodec_start(AMediaCodec *mData) { diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp index 6f69f8d..c08814f 100644 --- a/media/ndk/NdkMediaFormat.cpp +++ b/media/ndk/NdkMediaFormat.cpp @@ -41,14 +41,14 @@ struct AMediaFormat { extern "C" { // private functions for conversion to/from AMessage -AMediaFormat* AMediaFormat_fromMsg(void* data) { +AMediaFormat* AMediaFormat_fromMsg(const void* data) { ALOGV("private ctor"); AMediaFormat* mData = new AMediaFormat(); mData->mFormat = *((sp<AMessage>*)data); return mData; } -void AMediaFormat_getFormat(AMediaFormat* mData, void* dest) { +void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest) { *((sp<AMessage>*)dest) = mData->mFormat; } @@ -141,24 +141,30 @@ const char* AMediaFormat_toString(AMediaFormat *mData) { return mData->mDebug.string(); } -bool AMediaFormat_getInt32(AMediaFormat* mData, const char *name, int32_t *out) { - return mData->mFormat->findInt32(name, out); +bool AMediaFormat_getInt32(AMediaFormat* format, const char *name, int32_t *out) { + return format->mFormat->findInt32(name, out); } -bool AMediaFormat_getInt64(AMediaFormat* mData, const char *name, int64_t *out) { - return mData->mFormat->findInt64(name, out); +bool AMediaFormat_getInt64(AMediaFormat* format, const char *name, int64_t *out) { + return format->mFormat->findInt64(name, out); } -bool AMediaFormat_getFloat(AMediaFormat* mData, const char *name, float *out) { - return mData->mFormat->findFloat(name, out); +bool AMediaFormat_getFloat(AMediaFormat* format, const char *name, float *out) { + return format->mFormat->findFloat(name, out); } -bool AMediaFormat_getDouble(AMediaFormat* mData, const char *name, double *out) { - return mData->mFormat->findDouble(name, out); +bool AMediaFormat_getSize(AMediaFormat* format, const char *name, size_t *out) { + return format->mFormat->findSize(name, out); } -bool AMediaFormat_getSize(AMediaFormat* mData, const char *name, size_t *out) { - return mData->mFormat->findSize(name, out); +bool AMediaFormat_getBuffer(AMediaFormat* format, const char *name, void** data, size_t *outsize) { + sp<ABuffer> buf; + if (format->mFormat->findBuffer(name, &buf)) { + *data = buf->data() + buf->offset(); + *outsize = buf->size(); + return true; + } + return false; } bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char **out) { @@ -180,6 +186,34 @@ bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char ** return false; } +void AMediaFormat_setInt32(AMediaFormat* format, const char *name, int32_t value) { + format->mFormat->setInt32(name, value); +} + +void AMediaFormat_setInt64(AMediaFormat* format, const char *name, int64_t value) { + format->mFormat->setInt64(name, value); +} + +void AMediaFormat_setFloat(AMediaFormat* format, const char* name, float value) { + format->mFormat->setFloat(name, value); +} + +void AMediaFormat_setString(AMediaFormat* format, const char* name, const char* value) { + // AMessage::setString() makes a copy of the string + format->mFormat->setString(name, value, strlen(value)); +} + +void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data, size_t size) { + // the ABuffer(void*, size_t) constructor doesn't take ownership of the data, so create + // a new buffer and copy the data into it + sp<ABuffer> buf = new ABuffer(size); + memcpy(buf->data(), data, size); + buf->setRange(0, size); + // AMessage::setBuffer() increases the refcount of the buffer + format->mFormat->setBuffer(name, buf); +} + + const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile"; const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate"; const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count"; diff --git a/media/ndk/NdkMediaFormatPriv.h b/media/ndk/NdkMediaFormatPriv.h index f67e782..02342d9 100644 --- a/media/ndk/NdkMediaFormatPriv.h +++ b/media/ndk/NdkMediaFormatPriv.h @@ -34,7 +34,7 @@ extern "C" { #endif AMediaFormat* AMediaFormat_fromMsg(void*); -void AMediaFormat_getFormat(AMediaFormat* mData, void* dest); +void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest); #ifdef __cplusplus } // extern "C" diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp new file mode 100644 index 0000000..98129cb --- /dev/null +++ b/media/ndk/NdkMediaMuxer.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2014 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_NDEBUG 0 +#define LOG_TAG "NdkMediaMuxer" + + +#include "NdkMediaMuxer.h" +#include "NdkMediaCodec.h" +#include "NdkMediaFormatPriv.h" + + +#include <utils/Log.h> +#include <utils/StrongPointer.h> +#include <media/stagefright/foundation/ABuffer.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/MediaMuxer.h> +#include <media/IMediaHTTPService.h> +#include <android_runtime/AndroidRuntime.h> +#include <android_util_Binder.h> + +#include <jni.h> + +using namespace android; + +static int translate_error(status_t err) { + if (err == OK) { + return OK; + } + ALOGE("sf error code: %d", err); + return -1000; +} + +struct AMediaMuxer { + sp<MediaMuxer> mImpl; + +}; + +extern "C" { + +AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) { + ALOGV("ctor"); + AMediaMuxer *mData = new AMediaMuxer(); + mData->mImpl = new MediaMuxer(fd, (android::MediaMuxer::OutputFormat)format); + return mData; +} + +int AMediaMuxer_delete(AMediaMuxer *muxer) { + ALOGV("dtor"); + delete muxer; + return OK; +} + +int AMediaMuxer_setLocation(AMediaMuxer *muxer, float latitude, float longtitude) { + return translate_error(muxer->mImpl->setLocation(latitude * 10000, longtitude * 10000)); +} + +int AMediaMuxer_setOrientationHint(AMediaMuxer *muxer, int degrees) { + return translate_error(muxer->mImpl->setOrientationHint(degrees)); +} + +ssize_t AMediaMuxer_addTrack(AMediaMuxer *muxer, const AMediaFormat *format) { + sp<AMessage> msg; + AMediaFormat_getFormat(format, &msg); + return translate_error(muxer->mImpl->addTrack(msg)); +} + +int AMediaMuxer_start(AMediaMuxer *muxer) { + return translate_error(muxer->mImpl->start()); +} + +int AMediaMuxer_stop(AMediaMuxer *muxer) { + return translate_error(muxer->mImpl->stop()); +} + +int AMediaMuxer_writeSampleData(AMediaMuxer *muxer, + size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info) { + sp<ABuffer> buf = new ABuffer((void*)(data + info.offset), info.size); + return translate_error( + muxer->mImpl->writeSampleData(buf, trackIdx, info.presentationTimeUs, info.flags)); +} + + +} // extern "C" + diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index be37436..2c5a0eb 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -143,6 +143,12 @@ static const int kPriorityFastMixer = 3; // See the client's minBufCount and mNotificationFramesAct calculations for details. static const int kFastTrackMultiplier = 2; +// See Thread::readOnlyHeap(). +// Initially this heap is used to allocate client buffers for "fast" AudioRecord. +// Eventually it will be the single buffer that FastCapture writes into via HAL read(), +// and that all "fast" AudioRecord clients read from. In either case, the size can be small. +static const size_t kRecordThreadReadOnlyHeapSize = 0x1000; + // ---------------------------------------------------------------------------- #ifdef ADD_BATTERY_DATA @@ -4635,6 +4641,8 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, #ifdef TEE_SINK , mTeeSink(teeSink) #endif + , mReadOnlyHeap(new MemoryDealer(kRecordThreadReadOnlyHeapSize, + "RecordThreadRO", MemoryHeapBase::READ_ONLY)) { snprintf(mName, kNameLength, "AudioIn_%X", id); mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName); @@ -5102,8 +5110,8 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe // PCM data audio_is_linear_pcm(format) && // mono or stereo - ( (channelMask == AUDIO_CHANNEL_OUT_MONO) || - (channelMask == AUDIO_CHANNEL_OUT_STEREO) ) && + ( (channelMask == AUDIO_CHANNEL_IN_MONO) || + (channelMask == AUDIO_CHANNEL_IN_STEREO) ) && // hardware sample rate // FIXME actually the native hardware sample rate (sampleRate == mSampleRate) && diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 5617c0c..8ea8683 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -226,6 +226,13 @@ public: virtual status_t setSyncEvent(const sp<SyncEvent>& event) = 0; virtual bool isValidSyncEvent(const sp<SyncEvent>& event) const = 0; + // Return a reference to a per-thread heap which can be used to allocate IMemory + // objects that will be read-only to client processes, read/write to mediaserver, + // and shared by all client processes of the thread. + // The heap is per-thread rather than common across all threads, because + // clients can't be trusted not to modify the offset of the IMemory they receive. + // If a thread does not have such a heap, this method returns 0. + virtual sp<MemoryDealer> readOnlyHeap() const { return 0; } mutable Mutex mLock; @@ -947,6 +954,8 @@ public: virtual status_t initCheck() const { return (mInput == NULL) ? NO_INIT : NO_ERROR; } + virtual sp<MemoryDealer> readOnlyHeap() const { return mReadOnlyHeap; } + sp<AudioFlinger::RecordThread::RecordTrack> createRecordTrack_l( const sp<AudioFlinger::Client>& client, uint32_t sampleRate, @@ -1021,4 +1030,6 @@ private: // For dumpsys const sp<NBAIO_Sink> mTeeSink; + + const sp<MemoryDealer> mReadOnlyHeap; }; diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 45f98d2..fc9b81a 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -31,14 +31,16 @@ // active output devices in isStreamActiveRemotely() #define APM_AUDIO_OUT_DEVICE_REMOTE_ALL AUDIO_DEVICE_OUT_REMOTE_SUBMIX +#include <inttypes.h> +#include <math.h> + +#include <cutils/properties.h> #include <utils/Log.h> -#include "AudioPolicyManager.h" -#include <hardware/audio_effect.h> #include <hardware/audio.h> -#include <math.h> +#include <hardware/audio_effect.h> #include <hardware_legacy/audio_policy_conf.h> -#include <cutils/properties.h> #include <media/AudioParameter.h> +#include "AudioPolicyManager.h" namespace android { @@ -85,6 +87,7 @@ const StringToEnum sDeviceNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET), STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET), STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY), + STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE), }; const StringToEnum sFlagNameToEnumTable[] = { @@ -162,7 +165,6 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address) { - SortedVector <audio_io_handle_t> outputs; String8 address = String8(device_address); ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); @@ -172,6 +174,8 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, // handle output devices if (audio_is_output_device(device)) { + SortedVector <audio_io_handle_t> outputs; + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, address, 0); @@ -193,7 +197,7 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, if (checkOutputsForDevice(device, state, outputs, address) != NO_ERROR) { return INVALID_OPERATION; } - ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs", + ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %zu outputs", outputs.size()); // register new device as available index = mAvailableOutputDevices.add(devDesc); @@ -265,9 +269,12 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, } else { return NO_ERROR; } - } + } // end if is output device + // handle input devices if (audio_is_input_device(device)) { + SortedVector <audio_io_handle_t> inputs; + sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device, address, 0); @@ -281,14 +288,17 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, ALOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } + if (checkInputsForDevice(device, state, inputs, address) != NO_ERROR) { + return INVALID_OPERATION; + } + index = mAvailableInputDevices.add(devDesc); if (index >= 0) { mAvailableInputDevices[index]->mId = nextUniqueId(); } else { return NO_MEMORY; } - } - break; + } break; // handle input device disconnection case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: { @@ -296,30 +306,19 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, ALOGW("setDeviceConnectionState() device not connected: %d", device); return INVALID_OPERATION; } + checkInputsForDevice(device, state, inputs, address); mAvailableInputDevices.remove(devDesc); - } break; + } break; default: ALOGE("setDeviceConnectionState() invalid state: %x", state); return BAD_VALUE; } - audio_io_handle_t activeInput = getActiveInput(); - if (activeInput != 0) { - AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput); - audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource); - if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) { - ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d", - inputDesc->mDevice, newDevice, activeInput); - inputDesc->mDevice = newDevice; - AudioParameter param = AudioParameter(); - param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); - mpClientInterface->setParameters(activeInput, param.toString()); - } - } + closeAllInputs(); return NO_ERROR; - } + } // end if is input device ALOGW("setDeviceConnectionState() invalid device: %x", device); return BAD_VALUE; @@ -1050,7 +1049,7 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, delete inputDesc; return 0; } - mInputs.add(input, inputDesc); + addInput(input, inputDesc); return input; } @@ -1152,6 +1151,13 @@ void AudioPolicyManager::releaseInput(audio_io_handle_t input) ALOGV("releaseInput() exit"); } +void AudioPolicyManager::closeAllInputs() { + for(size_t input_index = 0; input_index < mInputs.size(); input_index++) { + mpClientInterface->closeInput(mInputs.keyAt(input_index)); + } + mInputs.clear(); +} + void AudioPolicyManager::initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax) @@ -1247,7 +1253,7 @@ audio_io_handle_t AudioPolicyManager::selectOutputForEffects( for (size_t i = 0; i < outputs.size(); i++) { AudioOutputDescriptor *desc = mOutputs.valueFor(outputs[i]); - ALOGV("selectOutputForEffects outputs[%d] flags %x", i, desc->mFlags); + ALOGV("selectOutputForEffects outputs[%zu] flags %x", i, desc->mFlags); if ((desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) { outputOffloaded = outputs[i]; } @@ -1484,7 +1490,7 @@ status_t AudioPolicyManager::dump(int fd) snprintf(buffer, SIZE, "\nHW Modules dump:\n"); write(fd, buffer, strlen(buffer)); for (size_t i = 0; i < mHwModules.size(); i++) { - snprintf(buffer, SIZE, "- HW Module %d:\n", i + 1); + snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1); write(fd, buffer, strlen(buffer)); mHwModules[i]->dump(fd); } @@ -1511,7 +1517,7 @@ status_t AudioPolicyManager::dump(int fd) " Stream Can be muted Index Min Index Max Index Cur [device : index]...\n"); write(fd, buffer, strlen(buffer)); for (int i = 0; i < AUDIO_STREAM_CNT; i++) { - snprintf(buffer, SIZE, " %02d ", i); + snprintf(buffer, SIZE, " %02zu ", i); write(fd, buffer, strlen(buffer)); mStreams[i].dump(fd); } @@ -1538,7 +1544,7 @@ status_t AudioPolicyManager::dump(int fd) bool AudioPolicyManager::isOffloadSupported(const audio_offload_info_t& offloadInfo) { ALOGV("isOffloadSupported: SR=%u, CM=0x%x, Format=0x%x, StreamType=%d," - " BitRate=%u, duration=%lld us, has_video=%d", + " BitRate=%u, duration=%" PRId64 " us, has_video=%d", offloadInfo.sample_rate, offloadInfo.channel_mask, offloadInfo.format, offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us, @@ -1680,10 +1686,10 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa mHwModules[i]->mName); delete outputDesc; } else { - for (size_t i = 0; i < outProfile->mSupportedDevices.size(); i++) { - audio_devices_t type = outProfile->mSupportedDevices[i]->mType; + for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) { + audio_devices_t type = outProfile->mSupportedDevices[k]->mType; ssize_t index = - mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[i]); + mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]); // give a valid ID to an attached device once confirmed it is reachable if ((index >= 0) && (mAvailableOutputDevices[index]->mId == 0)) { mAvailableOutputDevices[index]->mId = nextUniqueId(); @@ -1725,10 +1731,10 @@ AudioPolicyManager::AudioPolicyManager(AudioPolicyClientInterface *clientInterfa &inputDesc->mChannelMask); if (input != 0) { - for (size_t i = 0; i < inProfile->mSupportedDevices.size(); i++) { - audio_devices_t type = inProfile->mSupportedDevices[i]->mType; + for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) { + audio_devices_t type = inProfile->mSupportedDevices[k]->mType; ssize_t index = - mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[i]); + mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]); // give a valid ID to an attached device once confirmed it is reachable if ((index >= 0) && (mAvailableInputDevices[index]->mId == 0)) { mAvailableInputDevices[index]->mId = nextUniqueId(); @@ -1978,6 +1984,11 @@ void AudioPolicyManager::addOutput(audio_io_handle_t id, AudioOutputDescriptor * mOutputs.add(id, outputDesc); } +void AudioPolicyManager::addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc) +{ + inputDesc->mId = id; + mInputs.add(id, inputDesc); +} String8 AudioPolicyManager::addressToParameter(audio_devices_t device, const String8 address) { @@ -2013,7 +2024,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { if (mHwModules[i]->mOutputProfiles[j]->mSupportedDevices.types() & device) { - ALOGV("checkOutputsForDevice(): adding profile %d from module %d", j, i); + ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i); profiles.add(mHwModules[i]->mOutputProfiles[j]); } } @@ -2058,84 +2069,99 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, desc->mFlags, &offloadInfo); if (output != 0) { + // Here is where the out_set_parameters() for card & device gets called if (!address.isEmpty()) { mpClientInterface->setParameters(output, addressToParameter(device, address)); } - if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { - String8 reply; - char *value; - if (profile->mSamplingRates[0] == 0) { - reply = mpClientInterface->getParameters(output, - String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)); - ALOGV("checkOutputsForDevice() direct output sup sampling rates %s", - reply.string()); - value = strpbrk((char *)reply.string(), "="); - if (value != NULL) { - loadSamplingRates(value + 1, profile); - } + // Here is where we step through and resolve any "dynamic" fields + String8 reply; + char *value; + if (profile->mSamplingRates[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)); + ALOGV("checkOutputsForDevice() direct output sup sampling rates %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadSamplingRates(value + 1, profile); } - if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { - reply = mpClientInterface->getParameters(output, - String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS)); - ALOGV("checkOutputsForDevice() direct output sup formats %s", - reply.string()); - value = strpbrk((char *)reply.string(), "="); - if (value != NULL) { - loadFormats(value + 1, profile); - } - } - if (profile->mChannelMasks[0] == 0) { - reply = mpClientInterface->getParameters(output, - String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS)); - ALOGV("checkOutputsForDevice() direct output sup channel masks %s", - reply.string()); - value = strpbrk((char *)reply.string(), "="); - if (value != NULL) { - loadOutChannels(value + 1, profile); - } + } + if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS)); + ALOGV("checkOutputsForDevice() direct output sup formats %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadFormats(value + 1, profile); } - if (((profile->mSamplingRates[0] == 0) && - (profile->mSamplingRates.size() < 2)) || - ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) && - (profile->mFormats.size() < 2)) || - ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) && - (profile->mChannelMasks.size() < 2))) { - ALOGW("checkOutputsForDevice() direct output missing param"); - mpClientInterface->closeOutput(output); - output = 0; - } else { - addOutput(output, desc); + } + if (profile->mChannelMasks[0] == 0) { + reply = mpClientInterface->getParameters(output, + String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS)); + ALOGV("checkOutputsForDevice() direct output sup channel masks %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadOutChannels(value + 1, profile); } - } else { - audio_io_handle_t duplicatedOutput = 0; - // add output descriptor + } + if (((profile->mSamplingRates[0] == 0) && + (profile->mSamplingRates.size() < 2)) || + ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) && + (profile->mFormats.size() < 2)) || + ((profile->mChannelMasks[0] == 0) && + (profile->mChannelMasks.size() < 2))) { + ALOGW("checkOutputsForDevice() direct output missing param"); + mpClientInterface->closeOutput(output); + output = 0; + } else if (profile->mSamplingRates[0] == 0) { + mpClientInterface->closeOutput(output); + desc->mSamplingRate = profile->mSamplingRates[1]; + offloadInfo.sample_rate = desc->mSamplingRate; + output = mpClientInterface->openOutput( + profile->mModule->mHandle, + &desc->mDevice, + &desc->mSamplingRate, + &desc->mFormat, + &desc->mChannelMask, + &desc->mLatency, + desc->mFlags, + &offloadInfo); + } + + if (output != 0) { addOutput(output, desc); - // set initial stream volume for device - applyStreamVolumes(output, device, 0, true); - - //TODO: configure audio effect output stage here - - // open a duplicating output thread for the new output and the primary output - duplicatedOutput = mpClientInterface->openDuplicateOutput(output, - mPrimaryOutput); - if (duplicatedOutput != 0) { - // add duplicated output descriptor - AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL); - dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput); - dupOutputDesc->mOutput2 = mOutputs.valueFor(output); - dupOutputDesc->mSamplingRate = desc->mSamplingRate; - dupOutputDesc->mFormat = desc->mFormat; - dupOutputDesc->mChannelMask = desc->mChannelMask; - dupOutputDesc->mLatency = desc->mLatency; - addOutput(duplicatedOutput, dupOutputDesc); - applyStreamVolumes(duplicatedOutput, device, 0, true); - } else { - ALOGW("checkOutputsForDevice() could not open dup output for %d and %d", - mPrimaryOutput, output); - mpClientInterface->closeOutput(output); - mOutputs.removeItem(output); - output = 0; + if ((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) == 0) { + audio_io_handle_t duplicatedOutput = 0; + + // set initial stream volume for device + applyStreamVolumes(output, device, 0, true); + + //TODO: configure audio effect output stage here + + // open a duplicating output thread for the new output and the primary output + duplicatedOutput = mpClientInterface->openDuplicateOutput(output, + mPrimaryOutput); + if (duplicatedOutput != 0) { + // add duplicated output descriptor + AudioOutputDescriptor *dupOutputDesc = new AudioOutputDescriptor(NULL); + dupOutputDesc->mOutput1 = mOutputs.valueFor(mPrimaryOutput); + dupOutputDesc->mOutput2 = mOutputs.valueFor(output); + dupOutputDesc->mSamplingRate = desc->mSamplingRate; + dupOutputDesc->mFormat = desc->mFormat; + dupOutputDesc->mChannelMask = desc->mChannelMask; + dupOutputDesc->mLatency = desc->mLatency; + addOutput(duplicatedOutput, dupOutputDesc); + applyStreamVolumes(duplicatedOutput, device, 0, true); + } else { + ALOGW("checkOutputsForDevice() could not open dup output for %d and %d", + mPrimaryOutput, output); + mpClientInterface->closeOutput(output); + mOutputs.removeItem(output); + output = 0; + } } } } @@ -2154,7 +2180,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, ALOGW("checkOutputsForDevice(): No output available for device %04x", device); return BAD_VALUE; } - } else { + } else { // Disconnect // check if one opened output is not needed any more after disconnecting one device for (size_t i = 0; i < mOutputs.size(); i++) { desc = mOutputs.valueAt(i); @@ -2165,6 +2191,7 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, outputs.add(mOutputs.keyAt(i)); } } + // Clear any profiles associated with the disconnected device. for (size_t i = 0; i < mHwModules.size(); i++) { if (mHwModules[i]->mHandle == 0) { @@ -2173,10 +2200,9 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) { IOProfile *profile = mHwModules[i]->mOutputProfiles[j]; - if ((profile->mSupportedDevices.types() & device) && - (profile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) { - ALOGV("checkOutputsForDevice(): clearing direct output profile %d on module %d", - j, i); + if (profile->mSupportedDevices.types() & device) { + ALOGV("checkOutputsForDevice(): " + "clearing direct output profile %zu on module %zu", j, i); if (profile->mSamplingRates[0] == 0) { profile->mSamplingRates.clear(); profile->mSamplingRates.add(0); @@ -2196,6 +2222,183 @@ status_t AudioPolicyManager::checkOutputsForDevice(audio_devices_t device, return NO_ERROR; } +status_t AudioPolicyManager::checkInputsForDevice(audio_devices_t device, + audio_policy_dev_state_t state, + SortedVector<audio_io_handle_t>& inputs, + const String8 address) +{ + AudioInputDescriptor *desc; + if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) { + // first list already open inputs that can be routed to this device + for (size_t input_index = 0; input_index < mInputs.size(); input_index++) { + desc = mInputs.valueAt(input_index); + if (desc->mProfile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) { + ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index)); + inputs.add(mInputs.keyAt(input_index)); + } + } + + // then look for input profiles that can be routed to this device + SortedVector<IOProfile *> profiles; + for (size_t module_idx = 0; module_idx < mHwModules.size(); module_idx++) + { + if (mHwModules[module_idx]->mHandle == 0) { + continue; + } + for (size_t profile_index = 0; + profile_index < mHwModules[module_idx]->mInputProfiles.size(); + profile_index++) + { + if (mHwModules[module_idx]->mInputProfiles[profile_index]->mSupportedDevices.types() + & (device & ~AUDIO_DEVICE_BIT_IN)) { + ALOGV("checkInputsForDevice(): adding profile %d from module %d", + profile_index, module_idx); + profiles.add(mHwModules[module_idx]->mInputProfiles[profile_index]); + } + } + } + + if (profiles.isEmpty() && inputs.isEmpty()) { + ALOGW("checkInputsForDevice(): No input available for device 0x%X", device); + return BAD_VALUE; + } + + // open inputs for matching profiles if needed. Direct inputs are also opened to + // query for dynamic parameters and will be closed later by setDeviceConnectionState() + for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) { + + IOProfile *profile = profiles[profile_index]; + // nothing to do if one input is already opened for this profile + size_t input_index; + for (input_index = 0; input_index < mInputs.size(); input_index++) { + desc = mInputs.valueAt(input_index); + if (desc->mProfile == profile) { + break; + } + } + if (input_index != mInputs.size()) { + continue; + } + + ALOGV("opening input for device 0x%X with params %s", device, address.string()); + desc = new AudioInputDescriptor(profile); + desc->mDevice = device; + + audio_io_handle_t input = mpClientInterface->openInput(profile->mModule->mHandle, + &desc->mDevice, + &desc->mSamplingRate, + &desc->mFormat, + &desc->mChannelMask); + + if (input != 0) { + if (!address.isEmpty()) { + mpClientInterface->setParameters(input, addressToParameter(device, address)); + } + + // Here is where we step through and resolve any "dynamic" fields + String8 reply; + char *value; + if (profile->mSamplingRates[0] == 0) { + reply = mpClientInterface->getParameters(input, + String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)); + ALOGV("checkInputsForDevice() direct input sup sampling rates %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadSamplingRates(value + 1, profile); + } + } + if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { + reply = mpClientInterface->getParameters(input, + String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS)); + ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadFormats(value + 1, profile); + } + } + if (profile->mChannelMasks[0] == 0) { + reply = mpClientInterface->getParameters(input, + String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS)); + ALOGV("checkInputsForDevice() direct input sup channel masks %s", + reply.string()); + value = strpbrk((char *)reply.string(), "="); + if (value != NULL) { + loadInChannels(value + 1, profile); + } + } + if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) || + ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) || + ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) { + ALOGW("checkInputsForDevice() direct input missing param"); + mpClientInterface->closeInput(input); + input = 0; + } + + if (input != 0) { + addInput(input, desc); + } + } // endif input != 0 + + if (input == 0) { + ALOGW("checkInputsForDevice() could not open input for device 0x%X", device); + delete desc; + profiles.removeAt(profile_index); + profile_index--; + } else { + inputs.add(input); + ALOGV("checkInputsForDevice(): adding input %d", input); + } + } // end scan profiles + + if (profiles.isEmpty()) { + ALOGW("checkInputsForDevice(): No input available for device 0x%X", device); + return BAD_VALUE; + } + } else { + // Disconnect + // check if one opened input is not needed any more after disconnecting one device + for (size_t input_index = 0; input_index < mInputs.size(); input_index++) { + desc = mInputs.valueAt(input_index); + if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types())) { + ALOGV("checkInputsForDevice(): disconnecting adding input %d", + mInputs.keyAt(input_index)); + inputs.add(mInputs.keyAt(input_index)); + } + } + // Clear any profiles associated with the disconnected device. + for (size_t module_index = 0; module_index < mHwModules.size(); module_index++) { + if (mHwModules[module_index]->mHandle == 0) { + continue; + } + for (size_t profile_index = 0; + profile_index < mHwModules[module_index]->mInputProfiles.size(); + profile_index++) { + IOProfile *profile = mHwModules[module_index]->mInputProfiles[profile_index]; + if (profile->mSupportedDevices.types() & device) { + ALOGV("checkInputsForDevice(): clearing direct input profile %d on module %d", + profile_index, module_index); + if (profile->mSamplingRates[0] == 0) { + profile->mSamplingRates.clear(); + profile->mSamplingRates.add(0); + } + if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) { + profile->mFormats.clear(); + profile->mFormats.add(AUDIO_FORMAT_DEFAULT); + } + if (profile->mChannelMasks[0] == 0) { + profile->mChannelMasks.clear(); + profile->mChannelMasks.add(0); + } + } + } + } + } // end disconnect + + return NO_ERROR; +} + + void AudioPolicyManager::closeOutput(audio_io_handle_t output) { ALOGV("closeOutput(%d)", output); @@ -2846,6 +3049,7 @@ AudioPolicyManager::IOProfile *AudioPolicyManager::getInputProfile(audio_devices for (size_t j = 0; j < mHwModules[i]->mInputProfiles.size(); j++) { IOProfile *profile = mHwModules[i]->mInputProfiles[j]; + // profile->log(); if (profile->isCompatibleProfile(device, samplingRate, format, channelMask, AUDIO_OUTPUT_FLAG_NONE)) { return profile; @@ -2878,6 +3082,8 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) { device = AUDIO_DEVICE_IN_WIRED_HEADSET; + } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) { + device = AUDIO_DEVICE_IN_USB_DEVICE; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { device = AUDIO_DEVICE_IN_BUILTIN_MIC; } @@ -3579,7 +3785,7 @@ status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd) // --- AudioInputDescriptor class implementation AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const IOProfile *profile) - : mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0), + : mId(0), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(0), mDevice(AUDIO_DEVICE_NONE), mRefCount(0), mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile) { @@ -3706,7 +3912,7 @@ void AudioPolicyManager::HwModule::dump(int fd) if (mOutputProfiles.size()) { write(fd, " - outputs:\n", strlen(" - outputs:\n")); for (size_t i = 0; i < mOutputProfiles.size(); i++) { - snprintf(buffer, SIZE, " output %d:\n", i); + snprintf(buffer, SIZE, " output %zu:\n", i); write(fd, buffer, strlen(buffer)); mOutputProfiles[i]->dump(fd); } @@ -3714,7 +3920,7 @@ void AudioPolicyManager::HwModule::dump(int fd) if (mInputProfiles.size()) { write(fd, " - inputs:\n", strlen(" - inputs:\n")); for (size_t i = 0; i < mInputProfiles.size(); i++) { - snprintf(buffer, SIZE, " input %d:\n", i); + snprintf(buffer, SIZE, " input %zu:\n", i); write(fd, buffer, strlen(buffer)); mInputProfiles[i]->dump(fd); } @@ -3824,6 +4030,32 @@ void AudioPolicyManager::IOProfile::dump(int fd) write(fd, result.string(), result.size()); } +void AudioPolicyManager::IOProfile::log() +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + ALOGV(" - sampling rates: "); + for (size_t i = 0; i < mSamplingRates.size(); i++) { + ALOGV(" %d", mSamplingRates[i]); + } + + ALOGV(" - channel masks: "); + for (size_t i = 0; i < mChannelMasks.size(); i++) { + ALOGV(" 0x%04x", mChannelMasks[i]); + } + + ALOGV(" - formats: "); + for (size_t i = 0; i < mFormats.size(); i++) { + ALOGV(" 0x%08x", mFormats[i]); + } + + ALOGV(" - devices: 0x%04x\n", mSupportedDevices.types()); + ALOGV(" - flags: 0x%04x\n", mFlags); +} + + // --- DeviceDescriptor implementation bool AudioPolicyManager::DeviceDescriptor::equals(const sp<DeviceDescriptor>& other) const diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index 8a631ba..f00fa8a 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -103,6 +103,7 @@ public: // indicates to the audio policy manager that the input stops being used. virtual status_t stopInput(audio_io_handle_t input); virtual void releaseInput(audio_io_handle_t input); + virtual void closeAllInputs(); virtual void initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax); @@ -246,6 +247,7 @@ protected: audio_output_flags_t flags) const; void dump(int fd); + void log(); // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats // indicates the supported parameters should be read from the output stream @@ -329,6 +331,7 @@ protected: status_t dump(int fd); + audio_io_handle_t mId; // input handle uint32_t mSamplingRate; // audio_format_t mFormat; // input configuration audio_channel_mask_t mChannelMask; // @@ -370,6 +373,7 @@ protected: }; void addOutput(audio_io_handle_t id, AudioOutputDescriptor *outputDesc); + void addInput(audio_io_handle_t id, AudioInputDescriptor *inputDesc); // return the strategy corresponding to a given stream type static routing_strategy getStrategy(audio_stream_type_t stream); @@ -453,6 +457,11 @@ protected: SortedVector<audio_io_handle_t>& outputs, const String8 address); + status_t checkInputsForDevice(audio_devices_t device, + audio_policy_dev_state_t state, + SortedVector<audio_io_handle_t>& inputs, + const String8 address); + // close an output and its companion duplicating output. void closeOutput(audio_io_handle_t output); diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp index 918c25c..2811475 100644 --- a/services/audiopolicy/AudioPolicyService.cpp +++ b/services/audiopolicy/AudioPolicyService.cpp @@ -122,10 +122,8 @@ AudioPolicyService::AudioPolicyService() AudioPolicyService::~AudioPolicyService() { mTonePlaybackThread->exit(); - mTonePlaybackThread.clear(); mAudioCommandThread->exit(); - mAudioCommandThread.clear(); - + mOutputCommandThread->exit(); // release audio pre processing resources for (size_t i = 0; i < mInputSources.size(); i++) { |