summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/IOMX.h2
-rw-r--r--include/ndk/NdkMediaCodec.h14
-rw-r--r--include/ndk/NdkMediaFormat.h22
-rw-r--r--include/ndk/NdkMediaMuxer.h75
-rw-r--r--media/libmedia/AudioRecord.cpp4
-rw-r--r--media/libstagefright/ACodec.cpp22
-rw-r--r--media/libstagefright/OMXCodec.cpp38
-rw-r--r--media/libstagefright/omx/OMX.cpp2
-rw-r--r--media/ndk/Android.mk1
-rw-r--r--media/ndk/NdkMediaCodec.cpp13
-rw-r--r--media/ndk/NdkMediaFormat.cpp58
-rw-r--r--media/ndk/NdkMediaFormatPriv.h2
-rw-r--r--media/ndk/NdkMediaMuxer.cpp99
-rw-r--r--services/audioflinger/Threads.cpp12
-rw-r--r--services/audioflinger/Threads.h11
-rw-r--r--services/audiopolicy/AudioPolicyManager.cpp460
-rw-r--r--services/audiopolicy/AudioPolicyManager.h9
-rw-r--r--services/audiopolicy/AudioPolicyService.cpp4
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++) {