Merge "Use audio_patch_handle_t in startAudioSource() and stopAudioSource()"
diff --git a/Android.bp b/Android.bp
index edd3d04..53f8bec 100644
--- a/Android.bp
+++ b/Android.bp
@@ -3,6 +3,7 @@
from: "include/camera/ndk/",
to: "camera",
srcs: ["include/camera/ndk/**/*.h"],
+ license: "NOTICE",
}
ndk_headers {
@@ -10,6 +11,7 @@
from: "include/ndk/",
to: "media",
srcs: ["include/ndk/**/*.h"],
+ license: "NOTICE",
}
subdirs = [
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
index 755ec8e..8308095 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl
@@ -44,4 +44,5 @@
* @param lastFrameNumber Frame number of the last frame of the streaming request.
*/
oneway void onRepeatingRequestError(in long lastFrameNumber);
+ oneway void onRequestQueueEmpty();
}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 7d78e2b..229b159 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1347,6 +1347,12 @@
}
binder::Status
+CameraDevice::ServiceCallback::onRequestQueueEmpty() {
+ // onRequestQueueEmpty not yet implemented in NDK
+ return binder::Status::ok();
+}
+
+binder::Status
CameraDevice::ServiceCallback::onRepeatingRequestError(int64_t lastFrameNumber) {
binder::Status ret = binder::Status::ok();
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 051462b..eb8028b 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -74,6 +74,7 @@
binder::Status onResultReceived(const CameraMetadata& metadata,
const CaptureResultExtras& resultExtras) override;
binder::Status onPrepared(int streamId) override;
+ binder::Status onRequestQueueEmpty() override;
binder::Status onRepeatingRequestError(int64_t lastFrameNumber) override;
private:
const wp<CameraDevice> mDevice;
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 828a758..b91e0f3 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -151,6 +151,7 @@
SENT_RESULT,
UNINITIALIZED,
REPEATING_REQUEST_ERROR,
+ REQUEST_QUEUE_EMPTY,
};
protected:
@@ -225,6 +226,14 @@
return binder::Status::ok();
}
+ virtual binder::Status onRequestQueueEmpty() {
+ Mutex::Autolock l(mLock);
+ mLastStatus = REQUEST_QUEUE_EMPTY;
+ mStatusesHit.push_back(mLastStatus);
+ mStatusCondition.broadcast();
+ return binder::Status::ok();
+ }
+
// Test helper functions:
bool hadError() const {
diff --git a/drm/libmediadrm/Drm.cpp b/drm/libmediadrm/Drm.cpp
index 9ab08db..07e9414 100644
--- a/drm/libmediadrm/Drm.cpp
+++ b/drm/libmediadrm/Drm.cpp
@@ -334,6 +334,7 @@
return -EINVAL;
}
+ setListener(NULL);
delete mPlugin;
mPlugin = NULL;
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 311119b..b902cf5 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -163,7 +163,7 @@
virtual status_t emptyGraphicBuffer(
buffer_id buffer,
const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
- OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) = 0;
+ OMX_TICKS timestamp, int fenceFd) = 0;
virtual status_t getExtensionIndex(
const char *parameter_name,
diff --git a/include/media/audiohal/DeviceHalInterface.h b/include/media/audiohal/DeviceHalInterface.h
index 2f7ed3a..caf01be 100644
--- a/include/media/audiohal/DeviceHalInterface.h
+++ b/include/media/audiohal/DeviceHalInterface.h
@@ -33,9 +33,6 @@
// Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
virtual status_t getSupportedDevices(uint32_t *devices) = 0;
- // Get the hardware module version.
- virtual status_t getVersion(uint32_t *version) = 0;
-
// Check to see if the audio hardware interface has been initialized.
virtual status_t initCheck() = 0;
@@ -88,6 +85,9 @@
audio_source_t source,
sp<StreamInHalInterface> *inStream) = 0;
+ // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
+ virtual status_t supportsAudioPatches(bool *supportsPatches) = 0;
+
// Creates an audio patch between several source and sink ports.
virtual status_t createAudioPatch(
unsigned int num_sources,
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
index 80f78b6..4b0f6a2 100644
--- a/media/audioserver/audioserver.rc
+++ b/media/audioserver/audioserver.rc
@@ -5,3 +5,4 @@
group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
ioprio rt 4
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+ onrestart restart audio-hal-2-0
\ No newline at end of file
diff --git a/media/libaudiohal/DeviceHalLocal.cpp b/media/libaudiohal/DeviceHalLocal.cpp
index c5df8c8..78adfef 100644
--- a/media/libaudiohal/DeviceHalLocal.cpp
+++ b/media/libaudiohal/DeviceHalLocal.cpp
@@ -40,11 +40,6 @@
return OK;
}
-status_t DeviceHalLocal::getVersion(uint32_t *version) {
- *version = mDev->common.version;
- return OK;
-}
-
status_t DeviceHalLocal::initCheck() {
return mDev->init_check(mDev);
}
@@ -139,17 +134,31 @@
return openResult;
}
+status_t DeviceHalLocal::supportsAudioPatches(bool *supportsPatches) {
+ *supportsPatches = version() >= AUDIO_DEVICE_API_VERSION_3_0;
+ return OK;
+}
+
status_t DeviceHalLocal::createAudioPatch(
unsigned int num_sources,
const struct audio_port_config *sources,
unsigned int num_sinks,
const struct audio_port_config *sinks,
audio_patch_handle_t *patch) {
- return mDev->create_audio_patch(mDev, num_sources, sources, num_sinks, sinks, patch);
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ return mDev->create_audio_patch(
+ mDev, num_sources, sources, num_sinks, sinks, patch);
+ } else {
+ return INVALID_OPERATION;
+ }
}
status_t DeviceHalLocal::releaseAudioPatch(audio_patch_handle_t patch) {
- return mDev->release_audio_patch(mDev, patch);
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ return mDev->release_audio_patch(mDev, patch);
+ } else {
+ return INVALID_OPERATION;
+ }
}
status_t DeviceHalLocal::getAudioPort(struct audio_port *port) {
@@ -157,7 +166,10 @@
}
status_t DeviceHalLocal::setAudioPortConfig(const struct audio_port_config *config) {
- return mDev->set_audio_port_config(mDev, config);
+ if (version() >= AUDIO_DEVICE_API_VERSION_3_0)
+ return mDev->set_audio_port_config(mDev, config);
+ else
+ return INVALID_OPERATION;
}
status_t DeviceHalLocal::dump(int fd) {
diff --git a/media/libaudiohal/DeviceHalLocal.h b/media/libaudiohal/DeviceHalLocal.h
index eba360c..865f296 100644
--- a/media/libaudiohal/DeviceHalLocal.h
+++ b/media/libaudiohal/DeviceHalLocal.h
@@ -28,9 +28,6 @@
// Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
virtual status_t getSupportedDevices(uint32_t *devices);
- // Get the hardware module version.
- virtual status_t getVersion(uint32_t *version);
-
// Check to see if the audio hardware interface has been initialized.
virtual status_t initCheck();
@@ -83,6 +80,9 @@
audio_source_t source,
sp<StreamInHalInterface> *inStream);
+ // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
+ virtual status_t supportsAudioPatches(bool *supportsPatches);
+
// Creates an audio patch between several source and sink ports.
virtual status_t createAudioPatch(
unsigned int num_sources,
@@ -115,6 +115,8 @@
// The destructor automatically closes the device.
virtual ~DeviceHalLocal();
+
+ uint32_t version() const { return mDev->common.version; }
};
} // namespace android
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 1901d8c..4bd1ab8 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -475,14 +475,13 @@
virtual status_t emptyGraphicBuffer(
buffer_id buffer,
const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
- OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
+ OMX_TICKS timestamp, int fenceFd) {
Parcel data, reply;
data.writeInterfaceToken(IOMXNode::getInterfaceDescriptor());
data.writeInt32((int32_t)buffer);
data.write(*graphicBuffer);
data.writeInt32(flags);
data.writeInt64(timestamp);
- data.writeInt64(origTimestamp);
data.writeInt32(fenceFd >= 0);
if (fenceFd >= 0) {
data.writeFileDescriptor(fenceFd, true /* takeOwnership */);
@@ -990,12 +989,10 @@
data.read(*graphicBuffer);
OMX_U32 flags = data.readInt32();
OMX_TICKS timestamp = data.readInt64();
- OMX_TICKS origTimestamp = data.readInt64();
bool haveFence = data.readInt32();
int fenceFd = haveFence ? ::dup(data.readFileDescriptor()) : -1;
reply->writeInt32(emptyGraphicBuffer(
- buffer, graphicBuffer, flags,
- timestamp, origTimestamp, fenceFd));
+ buffer, graphicBuffer, flags, timestamp, fenceFd));
return NO_ERROR;
}
diff --git a/media/libmedia/aidl/android/IGraphicBufferSource.aidl b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
index e9bf739..a8dd309 100644
--- a/media/libmedia/aidl/android/IGraphicBufferSource.aidl
+++ b/media/libmedia/aidl/android/IGraphicBufferSource.aidl
@@ -27,7 +27,6 @@
void configure(IOMXNode omxNode, int dataSpace);
void setSuspend(boolean suspend);
void setRepeatPreviousFrameDelayUs(long repeatAfterUs);
- void setMaxTimestampGapUs(long maxGapUs);
void setMaxFps(float maxFps);
void setTimeLapseConfig(long timePerFrameUs, long timePerCaptureUs);
void setStartTimeUs(long startTimeUs);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 822f154..c3274f0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -755,7 +755,7 @@
status_t NuPlayer::Decoder::fetchInputData(sp<AMessage> &reply) {
sp<ABuffer> accessUnit;
- bool dropAccessUnit;
+ bool dropAccessUnit = true;
do {
status_t err = mSource->dequeueAccessUnit(mIsAudio, &accessUnit);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index dbb5f0d..ed29859 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1723,8 +1723,12 @@
mRepeatFrameDelayUs = -1ll;
}
+ // only allow 32-bit value, since we pass it as U32 to OMX.
if (!msg->findInt64("max-pts-gap-to-encoder", &mMaxPtsGapUs)) {
mMaxPtsGapUs = -1ll;
+ } else if (mMaxPtsGapUs > INT32_MAX || mMaxPtsGapUs < 0) {
+ ALOGW("Unsupported value for max pts gap %lld", (long long) mMaxPtsGapUs);
+ mMaxPtsGapUs = -1ll;
}
if (!msg->findFloat("max-fps-to-encoder", &mMaxFps)) {
@@ -6569,9 +6573,14 @@
}
if (mCodec->mMaxPtsGapUs > 0ll) {
- err = statusFromBinderStatus(
- mCodec->mGraphicBufferSource->setMaxTimestampGapUs(
- mCodec->mMaxPtsGapUs));
+ OMX_PARAM_U32TYPE maxPtsGapParams;
+ InitOMXParams(&maxPtsGapParams);
+ maxPtsGapParams.nPortIndex = kPortIndexInput;
+ maxPtsGapParams.nU32 = (uint32_t) mCodec->mMaxPtsGapUs;
+
+ err = mCodec->mOMXNode->setParameter(
+ (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl,
+ &maxPtsGapParams, sizeof(maxPtsGapParams));
if (err != OK) {
ALOGE("[%s] Unable to configure max timestamp gap (err %d)",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 436a960..5ab5f3e 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1097,14 +1097,16 @@
break;
}
- case STOPPING:
case RELEASING:
{
// Ignore the error, assuming we'll still get
- // the shutdown complete notification.
-
+ // the shutdown complete notification. If we
+ // don't, we'll timeout and force release.
sendErrorResponse = false;
-
+ }
+ // fall-thru
+ case STOPPING:
+ {
if (mFlags & kFlagSawMediaServerDie) {
// MediaServer died, there definitely won't
// be a shutdown complete notification after
@@ -1118,6 +1120,7 @@
mComponentName.clear();
}
(new AMessage)->postReply(mReplyID);
+ sendErrorResponse = false;
}
break;
}
@@ -1573,6 +1576,10 @@
case CodecBase::kWhatShutdownCompleted:
{
+ if (mState == UNINITIALIZED) {
+ // Ignore shutdown complete if we're already released.
+ break;
+ }
if (mState == STOPPING) {
setState(INITIALIZED);
} else {
@@ -1894,7 +1901,9 @@
}
}
- if (!((mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED) // See 1
+ bool isReleasingAllocatedComponent =
+ (mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED;
+ if (!isReleasingAllocatedComponent // See 1
&& mState != INITIALIZED
&& mState != CONFIGURED && !isExecuting()) {
// 1) Permit release to shut down the component if allocated.
@@ -1918,6 +1927,14 @@
break;
}
+ // If we're flushing, or we're stopping but received a release
+ // request, post the reply for the pending call first, and consider
+ // it done. The reply token will be replaced after this, and we'll
+ // no longer be able to reply.
+ if (mState == FLUSHING || mState == STOPPING) {
+ (new AMessage)->postReply(mReplyID);
+ }
+
if (mFlags & kFlagSawMediaServerDie) {
// It's dead, Jim. Don't expect initiateShutdown to yield
// any useful results now...
@@ -1929,6 +1946,15 @@
break;
}
+ // If we already have an error, component may not be able to
+ // complete the shutdown properly. If we're stopping, post the
+ // reply now with an error to unblock the client, client can
+ // release after the failure (instead of ANR).
+ if (msg->what() == kWhatStop && (mFlags & kFlagStickyError)) {
+ PostReplyWithError(replyID, getStickyError());
+ break;
+ }
+
mReplyID = replyID;
setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
@@ -1940,6 +1966,7 @@
if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
pushBlankBuffersToNativeWindow(mSurface.get());
}
+
break;
}
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index d911508..bda29fa 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -99,7 +99,7 @@
status_t emptyGraphicBuffer(
OMX::buffer_id buffer,
const sp<GraphicBuffer> &graphicBuffer, OMX_U32 flags,
- OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd);
+ OMX_TICKS timestamp, int fenceFd);
status_t getExtensionIndex(
const char *parameterName, OMX_INDEXTYPE *index);
@@ -162,9 +162,13 @@
};
SecureBufferType mSecureBufferType[2];
+ // Following are OMX parameters managed by us (instead of the component)
+ // OMX_IndexParamMaxFrameDurationForBitrateControl
KeyedVector<int64_t, int64_t> mOriginalTimeUs;
- bool mShouldRestorePts;
bool mRestorePtsFailed;
+ int64_t mMaxTimestampGapUs;
+ int64_t mPrevOriginalTimeUs;
+ int64_t mPrevModifiedTimeUs;
// For debug support
char *mName;
@@ -250,6 +254,9 @@
bool handleDataSpaceChanged(omx_message &msg);
+ status_t setMaxPtsGapUs(const void *params, size_t size);
+ int64_t getCodecTimestamp(OMX_TICKS timestamp);
+
OMXNodeInstance(const OMXNodeInstance &);
OMXNodeInstance &operator=(const OMXNodeInstance &);
};
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index afb8173..4575d28 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -51,9 +51,7 @@
mNumBufferAcquired(0),
mEndOfStream(false),
mEndOfStreamSent(false),
- mMaxTimestampGapUs(-1ll),
mPrevOriginalTimeUs(-1ll),
- mPrevModifiedTimeUs(-1ll),
mSkipFramesBeforeNs(-1ll),
mRepeatAfterUs(-1ll),
mRepeatLastFrameGeneration(0),
@@ -515,9 +513,7 @@
}
bool GraphicBufferSource::getTimestamp(
- const BufferItem &item, int64_t *origTimeUs, int64_t *codecTimeUs) {
- *origTimeUs = -1ll;
-
+ const BufferItem &item, int64_t *codecTimeUs) {
int64_t timeUs = item.mTimestamp / 1000;
timeUs += mInputBufferTimeOffsetUs;
@@ -558,29 +554,7 @@
return false;
}
- if (mMaxTimestampGapUs > 0ll) {
- //TODO: Fix the case when mMaxTimestampGapUs and mTimePerCaptureUs are both set.
-
- /* Cap timestamp gap between adjacent frames to specified max
- *
- * In the scenario of cast mirroring, encoding could be suspended for
- * prolonged periods. Limiting the pts gap to workaround the problem
- * where encoder's rate control logic produces huge frames after a
- * long period of suspension.
- */
- if (mPrevOriginalTimeUs >= 0ll) {
- int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
- timeUs = (timestampGapUs < mMaxTimestampGapUs ?
- timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
- }
- *origTimeUs = originalTimeUs;
- ALOGV("IN timestamp: %lld -> %lld",
- static_cast<long long>(originalTimeUs),
- static_cast<long long>(timeUs));
- }
-
mPrevOriginalTimeUs = originalTimeUs;
- mPrevModifiedTimeUs = timeUs;
}
*codecTimeUs = timeUs;
@@ -590,8 +564,8 @@
status_t GraphicBufferSource::submitBuffer_l(const BufferItem &item, int cbi) {
ALOGV("submitBuffer_l: slot=%d, cbi=%d", item.mSlot, cbi);
- int64_t origTimeUs, codecTimeUs;
- if (!getTimestamp(item, &origTimeUs, &codecTimeUs)) {
+ int64_t codecTimeUs;
+ if (!getTimestamp(item, &codecTimeUs)) {
return UNKNOWN_ERROR;
}
@@ -605,8 +579,7 @@
int fenceID = item.mFence->isValid() ? item.mFence->dup() : -1;
status_t err = mOMXNode->emptyGraphicBuffer(
- bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME,
- codecTimeUs, origTimeUs, fenceID);
+ bufferID, buffer, OMX_BUFFERFLAG_ENDOFFRAME, codecTimeUs, fenceID);
if (err != OK) {
ALOGW("WARNING: emptyGraphicBuffer failed: 0x%x", err);
@@ -641,7 +614,7 @@
status_t err = mOMXNode->emptyGraphicBuffer(
bufferID, NULL /* buffer */,
OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS,
- 0 /* timestamp */, -1ll /* origTimestamp */, -1 /* fenceFd */);
+ 0 /* timestamp */, -1 /* fenceFd */);
if (err != OK) {
ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);
} else {
@@ -855,9 +828,7 @@
mSuspended = false;
mEndOfStream = false;
mEndOfStreamSent = false;
- mMaxTimestampGapUs = -1ll;
mPrevOriginalTimeUs = -1ll;
- mPrevModifiedTimeUs = -1ll;
mSkipFramesBeforeNs = -1ll;
mRepeatAfterUs = -1ll;
mRepeatLastFrameGeneration = 0;
@@ -928,20 +899,6 @@
return Status::ok();
}
-Status GraphicBufferSource::setMaxTimestampGapUs(int64_t maxGapUs) {
- ALOGV("setMaxTimestampGapUs: maxGapUs=%lld", (long long)maxGapUs);
-
- Mutex::Autolock autoLock(mMutex);
-
- if (mExecuting || maxGapUs <= 0ll) {
- return Status::fromServiceSpecificError(INVALID_OPERATION);
- }
-
- mMaxTimestampGapUs = maxGapUs;
-
- return Status::ok();
-}
-
Status GraphicBufferSource::setTimeOffsetUs(int64_t timeOffsetUs) {
Mutex::Autolock autoLock(mMutex);
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 045a86a..80fe078 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -120,15 +120,6 @@
// state and once this behaviour is specified it cannot be reset.
Status setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) override;
- // When set, the timestamp fed to the encoder will be modified such that
- // the gap between two adjacent frames is capped at maxGapUs. Timestamp
- // will be restored to the original when the encoded frame is returned to
- // the client.
- // This is to solve a problem in certain real-time streaming case, where
- // encoder's rate control logic produces huge frames after a long period
- // of suspension on input.
- Status setMaxTimestampGapUs(int64_t maxGapUs) override;
-
// Sets the input buffer timestamp offset.
// When set, the sample's timestamp will be adjusted with the timeOffsetUs.
Status setTimeOffsetUs(int64_t timeOffsetUs) override;
@@ -220,7 +211,7 @@
void setLatestBuffer_l(const BufferItem &item);
bool repeatLatestBuffer_l();
- bool getTimestamp(const BufferItem &item, int64_t *timeUs, int64_t *codecTimeUs);
+ bool getTimestamp(const BufferItem &item, int64_t *codecTimeUs);
// called when the data space of the input buffer changes
void onDataSpaceChanged_l(android_dataspace dataSpace, android_pixel_format pixelFormat);
@@ -279,9 +270,7 @@
kRepeatLastFrameCount = 10,
};
- int64_t mMaxTimestampGapUs;
int64_t mPrevOriginalTimeUs;
- int64_t mPrevModifiedTimeUs;
int64_t mSkipFramesBeforeNs;
sp<FrameDropper> mFrameDropper;
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 2a4bd15..41f3e4a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -340,8 +340,10 @@
mQueriedProhibitedExtensions(false),
mQuirks(0),
mBufferIDCount(0),
- mShouldRestorePts(false),
- mRestorePtsFailed(false)
+ mRestorePtsFailed(false),
+ mMaxTimestampGapUs(-1ll),
+ mPrevOriginalTimeUs(-1ll),
+ mPrevModifiedTimeUs(-1ll)
{
mName = ADebug::GetDebugName(name);
DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
@@ -546,18 +548,17 @@
"OMX.google.android.index.getAndroidNativeBufferUsage",
};
- if ((index > OMX_IndexComponentStartUnused && index <= OMX_IndexParamStandardComponentRole)
- || (index > OMX_IndexPortStartUnused && index <= OMX_IndexParamCompBufferSupplier)
- || (index > OMX_IndexAudioStartUnused && index <= OMX_IndexConfigAudioChannelVolume)
- || (index > OMX_IndexVideoStartUnused && index <= OMX_IndexConfigVideoNalSize)
- || (index > OMX_IndexCommonStartUnused
- && index <= OMX_IndexConfigCommonTransitionEffect)
+ if ((index > OMX_IndexComponentStartUnused && index < OMX_IndexComponentEndUnused)
+ || (index > OMX_IndexPortStartUnused && index < OMX_IndexPortEndUnused)
+ || (index > OMX_IndexAudioStartUnused && index < OMX_IndexAudioEndUnused)
+ || (index > OMX_IndexVideoStartUnused && index < OMX_IndexVideoEndUnused)
+ || (index > OMX_IndexCommonStartUnused && index < OMX_IndexCommonEndUnused)
|| (index > (OMX_INDEXTYPE)OMX_IndexExtAudioStartUnused
- && index <= (OMX_INDEXTYPE)OMX_IndexParamAudioProfileQuerySupported)
+ && index < (OMX_INDEXTYPE)OMX_IndexExtAudioEndUnused)
|| (index > (OMX_INDEXTYPE)OMX_IndexExtVideoStartUnused
- && index <= (OMX_INDEXTYPE)OMX_IndexConfigAndroidVideoTemporalLayering)
+ && index < (OMX_INDEXTYPE)OMX_IndexExtVideoEndUnused)
|| (index > (OMX_INDEXTYPE)OMX_IndexExtOtherStartUnused
- && index <= (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits)) {
+ && index < (OMX_INDEXTYPE)OMX_IndexExtOtherEndUnused)) {
return false;
}
@@ -598,6 +599,10 @@
OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
+ if (extIndex == OMX_IndexParamMaxFrameDurationForBitrateControl) {
+ return setMaxPtsGapUs(params, size);
+ }
+
if (isProhibitedIndex_l(index)) {
android_errorWriteLog(0x534e4554, "29422020");
return BAD_INDEX;
@@ -1524,7 +1529,7 @@
// like emptyBuffer, but the data is already in header->pBuffer
status_t OMXNodeInstance::emptyGraphicBuffer(
OMX::buffer_id buffer, const sp<GraphicBuffer> &graphicBuffer,
- OMX_U32 flags, OMX_TICKS timestamp, OMX_TICKS origTimestamp, int fenceFd) {
+ OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
Mutex::Autolock autoLock(mLock);
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer, kPortIndexInput);
@@ -1541,13 +1546,7 @@
return err;
}
- // If we're required to restore original timestamp, origTimestamp will
- // be set to non-negative number for all frames. If it's not required
- // client will set it to -1ll for all frames.
- if (origTimestamp >= 0ll && !mRestorePtsFailed) {
- mShouldRestorePts = true;
- mOriginalTimeUs.add(timestamp, origTimestamp);
- }
+ int64_t codecTimeUs = getCodecTimestamp(timestamp);
header->nOffset = 0;
if (graphicBuffer == NULL) {
@@ -1557,13 +1556,55 @@
} else {
header->nFilledLen = sizeof(VideoNativeMetadata);
}
- return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer, fenceFd);
+ return emptyBuffer_l(header, flags, codecTimeUs, (intptr_t)header->pBuffer, fenceFd);
+}
+
+status_t OMXNodeInstance::setMaxPtsGapUs(const void *params, size_t size) {
+ if (params == NULL || size != sizeof(OMX_PARAM_U32TYPE)) {
+ CLOG_ERROR(setMaxPtsGapUs, BAD_VALUE, "invalid params (%p,%zu)", params, size);
+ return BAD_VALUE;
+ }
+
+ mMaxTimestampGapUs = (int64_t)((OMX_PARAM_U32TYPE*)params)->nU32;
+
+ return OK;
+}
+
+int64_t OMXNodeInstance::getCodecTimestamp(OMX_TICKS timestamp) {
+ int64_t originalTimeUs = timestamp;
+
+ if (mMaxTimestampGapUs > 0ll) {
+ /* Cap timestamp gap between adjacent frames to specified max
+ *
+ * In the scenario of cast mirroring, encoding could be suspended for
+ * prolonged periods. Limiting the pts gap to workaround the problem
+ * where encoder's rate control logic produces huge frames after a
+ * long period of suspension.
+ */
+ if (mPrevOriginalTimeUs >= 0ll) {
+ int64_t timestampGapUs = originalTimeUs - mPrevOriginalTimeUs;
+ timestamp = (timestampGapUs < mMaxTimestampGapUs ?
+ timestampGapUs : mMaxTimestampGapUs) + mPrevModifiedTimeUs;
+ }
+ ALOGV("IN timestamp: %lld -> %lld",
+ static_cast<long long>(originalTimeUs),
+ static_cast<long long>(timestamp));
+ }
+
+ mPrevOriginalTimeUs = originalTimeUs;
+ mPrevModifiedTimeUs = timestamp;
+
+ if (mMaxTimestampGapUs > 0ll && !mRestorePtsFailed) {
+ mOriginalTimeUs.add(timestamp, originalTimeUs);
+ }
+
+ return timestamp;
}
void OMXNodeInstance::codecBufferFilled(omx_message &msg) {
Mutex::Autolock autoLock(mBufferIDLock);
- if (!mShouldRestorePts || mRestorePtsFailed) {
+ if (mMaxTimestampGapUs <= 0ll || mRestorePtsFailed) {
return;
}
@@ -1583,12 +1624,6 @@
ALOGW("giving up limiting timestamp gap (pts = %lld)", timestamp);
mRestorePtsFailed = true;
}
- if (mOriginalTimeUs.size() > BufferQueue::NUM_BUFFER_SLOTS) {
- // something terribly wrong must have happened, giving up...
- ALOGE("mOriginalTimeUs has too many entries (%zu)",
- mOriginalTimeUs.size());
- mRestorePtsFailed = true;
- }
}
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 6c71f60..04fb8ba 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -67,8 +67,6 @@
#include <mediautils/BatteryNotifier.h>
#include <private/android_filesystem_config.h>
-#include <hardware/audio.h> // for AUDIO_HARDWARE_MODULE_...
-
// ----------------------------------------------------------------------------
// Note: the following macro is used for extremely verbose logging message. In
diff --git a/services/audioflinger/AudioHwDevice.cpp b/services/audioflinger/AudioHwDevice.cpp
index 28110a2..b109d06 100644
--- a/services/audioflinger/AudioHwDevice.cpp
+++ b/services/audioflinger/AudioHwDevice.cpp
@@ -93,10 +93,10 @@
return status;
}
-uint32_t AudioHwDevice::version() const
-{
- uint32_t result;
- return mHwDevice->getVersion(&result) == OK ? result : 0;
+bool AudioHwDevice::supportsAudioPatches() const {
+ bool result;
+ return mHwDevice->supportsAudioPatches(&result) == OK ? result : false;
}
+
}; // namespace android
diff --git a/services/audioflinger/AudioHwDevice.h b/services/audioflinger/AudioHwDevice.h
index ebb8911..eb826c6 100644
--- a/services/audioflinger/AudioHwDevice.h
+++ b/services/audioflinger/AudioHwDevice.h
@@ -58,7 +58,6 @@
audio_module_handle_t handle() const { return mHandle; }
const char *moduleName() const { return mModuleName; }
sp<DeviceHalInterface> hwDevice() const { return mHwDevice; }
- uint32_t version() const;
/** This method creates and opens the audio hardware output stream.
* The "address" parameter qualifies the "devices" audio device type if needed.
@@ -75,6 +74,8 @@
struct audio_config *config,
const char *address);
+ bool supportsAudioPatches() const;
+
private:
const audio_module_handle_t mHandle;
const char * const mModuleName;
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 93f634a..591a49e 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -27,8 +27,6 @@
#include "ServiceUtilities.h"
#include <media/AudioParameter.h>
-#include <hardware/audio.h> // for AUDIO_DEVICE_API_VERSION_...
-
// ----------------------------------------------------------------------------
// Note: the following macro is used for extremely verbose logging message. In
@@ -249,11 +247,11 @@
// - special patch request with 2 sources (reuse one existing output mix) OR
// - Device to device AND
// - source HW module != destination HW module OR
- // - audio HAL version < 3.0
+ // - audio HAL does not support audio patches creation
if ((patch->num_sources == 2) ||
((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
((patch->sinks[0].ext.device.hw_module != srcModule) ||
- (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0)))) {
+ !audioHwDevice->supportsAudioPatches()))) {
if (patch->num_sources == 2) {
if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
(patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
@@ -341,17 +339,13 @@
}
status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
} else {
- if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) {
- status = INVALID_OPERATION;
- goto exit;
- }
-
sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
status = hwDevice->createAudioPatch(patch->num_sources,
patch->sources,
patch->num_sinks,
patch->sinks,
&halHandle);
+ if (status == INVALID_OPERATION) goto exit;
}
}
} break;
@@ -620,10 +614,6 @@
status = thread->sendReleaseAudioPatchConfigEvent(removedPatch->mHalHandle);
} else {
AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
- if (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) {
- status = INVALID_OPERATION;
- break;
- }
sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
status = hwDevice->releaseAudioPatch(removedPatch->mHalHandle);
}
@@ -688,13 +678,7 @@
}
AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
- if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
- sp<DeviceHalInterface> hwDevice = audioHwDevice->hwDevice();
- return hwDevice->setAudioPortConfig(config);
- } else {
- return INVALID_OPERATION;
- }
- return NO_ERROR;
+ return audioHwDevice->hwDevice()->setAudioPortConfig(config);
}
} // namespace android
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e661a3b..6b23e56 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -53,8 +53,6 @@
#include <powermanager/PowerManager.h>
-#include <hardware/audio.h> // for AUDIO_DEVICE_API_VERSION_...
-
#include "AudioFlinger.h"
#include "AudioMixer.h"
#include "BufferProviders.h"
@@ -3492,7 +3490,7 @@
mOutDevice = type;
mPatch = *patch;
- if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ if (mOutput->audioHwDev->supportsAudioPatches()) {
sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
status = hwDevice->createAudioPatch(patch->num_sources,
patch->sources,
@@ -3542,7 +3540,7 @@
mOutDevice = AUDIO_DEVICE_NONE;
- if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ if (mOutput->audioHwDev->supportsAudioPatches()) {
sp<DeviceHalInterface> hwDevice = mOutput->audioHwDev->hwDevice();
status = hwDevice->releaseAudioPatch(handle);
} else {
@@ -7612,7 +7610,7 @@
}
}
- if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ if (mInput->audioHwDev->supportsAudioPatches()) {
sp<DeviceHalInterface> hwDevice = mInput->audioHwDev->hwDevice();
status = hwDevice->createAudioPatch(patch->num_sources,
patch->sources,
@@ -7652,7 +7650,7 @@
mInDevice = AUDIO_DEVICE_NONE;
- if (mInput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
+ if (mInput->audioHwDev->supportsAudioPatches()) {
sp<DeviceHalInterface> hwDevice = mInput->audioHwDev->hwDevice();
status = hwDevice->releaseAudioPatch(handle);
} else {
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 99c0cd2..ded2285 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -118,7 +118,7 @@
audio_format_t targetFormat);
audio_module_handle_t getModuleHandle() const;
- uint32_t getModuleVersion() const;
+ uint32_t getModuleVersionMajor() const;
const char *getModuleName() const;
bool useInputChannelMask() const
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 3a31672..29b6b9c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -18,7 +18,6 @@
#include "DeviceDescriptor.h"
#include "AudioRoute.h"
-#include <hardware/audio.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Errors.h>
@@ -40,7 +39,7 @@
class HwModule : public RefBase
{
public:
- explicit HwModule(const char *name, uint32_t halVersion = AUDIO_DEVICE_API_VERSION_MIN);
+ explicit HwModule(const char *name, uint32_t halVersionMajor = 0, uint32_t halVersionMinor = 0);
~HwModule();
const char *getName() const { return mName.string(); }
@@ -55,8 +54,11 @@
void setProfiles(const IOProfileCollection &profiles);
- void setHalVersion(uint32_t halVersion) { mHalVersion = halVersion; }
- uint32_t getHalVersion() const { return mHalVersion; }
+ void setHalVersion(uint32_t major, uint32_t minor) {
+ mHalVersion = (major << 8) | (minor & 0xff);
+ }
+ uint32_t getHalVersionMajor() const { return mHalVersion >> 8; }
+ uint32_t getHalVersionMinor() const { return mHalVersion & 0xff; }
sp<DeviceDescriptor> getRouteSinkDevice(const sp<AudioRoute> &route) const;
DeviceVector getRouteSourceDevices(const sp<AudioRoute> &route) const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 31bf95c..aac23b4 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -50,12 +50,12 @@
return mModule->mHandle;
}
-uint32_t AudioPort::getModuleVersion() const
+uint32_t AudioPort::getModuleVersionMajor() const
{
if (mModule == 0) {
return 0;
}
- return mModule->getHalVersion();
+ return mModule->getHalVersionMajor();
}
const char *AudioPort::getModuleName() const
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 643ac1e..d751f07 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -357,9 +357,8 @@
} else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
uint32_t major, minor;
sscanf((char *)node->value, "%u.%u", &major, &minor);
- module->setHalVersion(HARDWARE_DEVICE_API_VERSION(major, minor));
- ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
- module->getHalVersion(), major, minor);
+ module->setHalVersion(major, minor);
+ ALOGV("loadGlobalConfig() mHalVersion = major %u minor %u", major, minor);
}
node = node->next;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 356aef1..cc56fb8 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -25,11 +25,11 @@
namespace android {
-HwModule::HwModule(const char *name, uint32_t halVersion)
+HwModule::HwModule(const char *name, uint32_t halVersionMajor, uint32_t halVersionMinor)
: mName(String8(name)),
- mHandle(AUDIO_MODULE_HANDLE_NONE),
- mHalVersion(halVersion)
+ mHandle(AUDIO_MODULE_HANDLE_NONE)
{
+ setHalVersion(halVersionMajor, halVersionMinor);
}
HwModule::~HwModule()
@@ -227,7 +227,7 @@
result.append(buffer);
snprintf(buffer, SIZE, " - handle: %d\n", mHandle);
result.append(buffer);
- snprintf(buffer, SIZE, " - version: %u.%u\n", mHalVersion >> 8, mHalVersion & 0xFF);
+ snprintf(buffer, SIZE, " - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
result.append(buffer);
write(fd, result.string(), result.size());
if (mOutputProfiles.size()) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 3e5bb7d..44f382b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -418,19 +418,17 @@
ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
return BAD_VALUE;
}
- uint32_t version = AUDIO_DEVICE_API_VERSION_MIN;
+ uint32_t versionMajor = 0, versionMinor = 0;
string versionLiteral = getXmlAttribute(root, Attributes::version);
if (!versionLiteral.empty()) {
- uint32_t major, minor;
- sscanf(versionLiteral.c_str(), "%u.%u", &major, &minor);
- version = HARDWARE_DEVICE_API_VERSION(major, minor);
- ALOGV("%s: mHalVersion = %04x major %u minor %u", __FUNCTION__,
- version, major, minor);
+ sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
+ ALOGV("%s: mHalVersion = major %u minor %u", __FUNCTION__,
+ versionMajor, versionMajor);
}
ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
- module = new Element(name.c_str(), version);
+ module = new Element(name.c_str(), versionMajor, versionMinor);
// Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
MixPortTraits::Collection mixPorts;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index d31429c..5f0557c 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -320,8 +320,7 @@
if (((availableInputDevices.types() &
AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) ||
(((txDevice & availPrimaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
- (primaryOutput->getAudioPort()->getModuleVersion() <
- AUDIO_DEVICE_API_VERSION_3_0))) {
+ (primaryOutput->getAudioPort()->getModuleVersionMajor() < 3))) {
availableOutputDevicesType = availPrimaryOutputDevices;
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 2d5afad..2f01b02 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -37,6 +37,7 @@
#include <media/AudioPolicyHelper.h>
#include <soundtrigger/SoundTrigger.h>
#include <system/audio.h>
+#include <audio_policy_conf.h>
#include "AudioPolicyManager.h"
#ifndef USE_XML_AUDIO_POLICY_CONF
#include <ConfigParsingUtils.h>
@@ -2721,7 +2722,7 @@
// - source and sink devices are on differnt HW modules OR
// - audio HAL version is < 3.0
if (!srcDeviceDesc->hasSameHwModuleAs(sinkDeviceDesc) ||
- (srcDeviceDesc->mModule->getHalVersion() < AUDIO_DEVICE_API_VERSION_3_0)) {
+ (srcDeviceDesc->mModule->getHalVersionMajor() < 3)) {
// support only one sink device for now to simplify output selection logic
if (patch->num_sinks > 1) {
return INVALID_OPERATION;
@@ -3083,7 +3084,7 @@
if (srcDeviceDesc->getAudioPort()->mModule->getHandle() ==
sinkDeviceDesc->getAudioPort()->mModule->getHandle() &&
- srcDeviceDesc->getAudioPort()->mModule->getHalVersion() >= AUDIO_DEVICE_API_VERSION_3_0 &&
+ srcDeviceDesc->getAudioPort()->mModule->getHalVersionMajor() >= 3 &&
srcDeviceDesc->getAudioPort()->mGains.size() > 0) {
ALOGV("%s AUDIO_DEVICE_API_VERSION_3_0", __FUNCTION__);
// create patch between src device and output device
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index b4f8e21..5166eb5 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1210,6 +1210,14 @@
}
}
+void CameraDeviceClient::notifyRequestQueueEmpty() {
+ // Thread safe. Don't bother locking.
+ sp<hardware::camera2::ICameraDeviceCallbacks> remoteCb = getRemoteCallback();
+ if (remoteCb != 0) {
+ remoteCb->onRequestQueueEmpty();
+ }
+}
+
void CameraDeviceClient::detachDevice() {
if (mDevice == 0) return;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index de283ea..68e453c 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -164,6 +164,7 @@
const CaptureResultExtras& resultExtras);
virtual void notifyShutter(const CaptureResultExtras& resultExtras, nsecs_t timestamp);
virtual void notifyPrepared(int streamId);
+ virtual void notifyRequestQueueEmpty();
virtual void notifyRepeatingRequestError(long lastFrameNumber);
/**
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index ccd1e4d..7e26153 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -307,6 +307,12 @@
}
template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyRequestQueueEmpty() {
+
+ ALOGV("%s: Request queue now empty", __FUNCTION__);
+}
+
+template <typename TClientBase>
void Camera2ClientBase<TClientBase>::notifyRepeatingRequestError(long lastFrameNumber) {
(void)lastFrameNumber;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index dbbf638..9fd0a78 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -73,6 +73,7 @@
virtual void notifyAutoWhitebalance(uint8_t newState,
int triggerId);
virtual void notifyPrepared(int streamId);
+ virtual void notifyRequestQueueEmpty();
virtual void notifyRepeatingRequestError(long lastFrameNumber);
int getCameraId() const;
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 984d84b..f30afe3 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -204,6 +204,7 @@
virtual void notifyShutter(const CaptureResultExtras &resultExtras,
nsecs_t timestamp) = 0;
virtual void notifyPrepared(int streamId) = 0;
+ virtual void notifyRequestQueueEmpty() = 0;
// Required only for API1
virtual void notifyAutoFocus(uint8_t newState, int triggerId) = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 73a4124..2f3251f 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -686,7 +686,8 @@
}
status_t Camera3Device::convertMetadataListToRequestListLocked(
- const List<const CameraMetadata> &metadataList, RequestList *requestList) {
+ const List<const CameraMetadata> &metadataList, bool repeating,
+ RequestList *requestList) {
if (requestList == NULL) {
CLOGE("requestList cannot be NULL.");
return BAD_VALUE;
@@ -701,6 +702,8 @@
return BAD_VALUE;
}
+ newRequest->mRepeating = repeating;
+
// Setup burst Id and request Id
newRequest->mResultExtras.burstId = burstId++;
if (it->exists(ANDROID_REQUEST_ID)) {
@@ -757,7 +760,8 @@
RequestList requestList;
- res = convertMetadataListToRequestListLocked(requests, /*out*/&requestList);
+ res = convertMetadataListToRequestListLocked(requests, repeating,
+ /*out*/&requestList);
if (res != OK) {
// error logged by previous call
return res;
@@ -3535,6 +3539,12 @@
mRequestQueue.begin();
nextRequest = *firstRequest;
mRequestQueue.erase(firstRequest);
+ if (mRequestQueue.empty() && !nextRequest->mRepeating) {
+ sp<NotificationListener> listener = mListener.promote();
+ if (listener != NULL) {
+ listener->notifyRequestQueueEmpty();
+ }
+ }
}
// In case we've been unpaused by setPaused clearing mDoPause, need to
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 33429a6..31901bc 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -297,6 +297,8 @@
// requests will be submitted to HAL at a time. The batch size for
// the following 7 requests will be ignored by the request thread.
int mBatchSize;
+ // Whether this request is from a repeating or repeating burst.
+ bool mRepeating;
};
typedef List<sp<CaptureRequest> > RequestList;
@@ -304,6 +306,7 @@
status_t convertMetadataListToRequestListLocked(
const List<const CameraMetadata> &metadataList,
+ bool repeating,
/*out*/
RequestList *requestList);
diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk
index c55ac7f..f719dc9 100644
--- a/services/soundtrigger/Android.mk
+++ b/services/soundtrigger/Android.mk
@@ -16,7 +16,6 @@
include $(CLEAR_VARS)
-
ifeq ($(SOUND_TRIGGER_USE_STUB_MODULE), 1)
LOCAL_CFLAGS += -DSOUND_TRIGGER_USE_STUB_MODULE
endif
@@ -35,12 +34,32 @@
libmedia \
libserviceutility
+
+ifeq ($(ENABLE_TREBLE),true)
+# Treble configuration
+LOCAL_CFLAGS += -DENABLE_TREBLE
+LOCAL_SRC_FILES += \
+ SoundTriggerHalHidl.cpp
+
+LOCAL_SHARED_LIBRARIES += \
+ libhwbinder \
+ libhidl \
+ libbase \
+ android.hardware.soundtrigger@2.0 \
+ android.hardware.audio.common@2.0
+else
+# libhardware configuration
+LOCAL_SRC_FILES += \
+ SoundTriggerHalLegacy.cpp
+endif
+
+
LOCAL_C_INCLUDES += \
$(TOPDIR)frameworks/av/services/audioflinger
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS += -Wall -Werror
LOCAL_MODULE:= libsoundtriggerservice
diff --git a/services/soundtrigger/SoundTriggerHalHidl.cpp b/services/soundtrigger/SoundTriggerHalHidl.cpp
new file mode 100644
index 0000000..e71d742
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalHidl.cpp
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoundTriggerHalHidl"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include "SoundTriggerHalHidl.h"
+#include <hidl/IServiceManager.h>
+#include <hwbinder/IPCThreadState.h>
+#include <hwbinder/ProcessState.h>
+
+namespace android {
+
+using android::hardware::Return;
+using android::hardware::ProcessState;
+using android::hardware::audio::common::V2_0::AudioDevice;
+
+pthread_once_t SoundTriggerHalHidl::sOnceControl = PTHREAD_ONCE_INIT;
+
+void SoundTriggerHalHidl::sOnceInit()
+{
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+}
+
+/* static */
+sp<SoundTriggerHalInterface> SoundTriggerHalInterface::connectModule(const char *moduleName)
+{
+ return new SoundTriggerHalHidl(moduleName);
+}
+
+int SoundTriggerHalHidl::getProperties(struct sound_trigger_properties *properties)
+{
+ sp<ISoundTriggerHw> soundtrigger = getService();
+ if (soundtrigger == 0) {
+ return -ENODEV;
+ }
+
+ ISoundTriggerHw::Properties halProperties;
+ Return<void> hidlReturn;
+ int32_t halReturn;
+ {
+ AutoMutex lock(mHalLock);
+ hidlReturn = soundtrigger->getProperties([&](int rc, auto res) {
+ halReturn = rc;
+ halProperties = res;
+ ALOGI("getProperties res implementor %s", res.implementor.c_str());
+ });
+ }
+
+ int ret = 0;
+ if (hidlReturn.getStatus().isOk()) {
+ convertPropertiesFromHal(properties, &halProperties);
+ } else {
+ ret = (int)hidlReturn.getStatus().transactionError();
+ if (ret == -EPIPE) {
+ clearService();
+ }
+ }
+
+ return ret;
+}
+
+int SoundTriggerHalHidl::loadSoundModel(struct sound_trigger_sound_model *sound_model,
+ sound_model_callback_t callback,
+ void *cookie,
+ sound_model_handle_t *handle)
+{
+ if (handle == NULL) {
+ return -EINVAL;
+ }
+
+ sp<ISoundTriggerHw> soundtrigger = getService();
+ if (soundtrigger == 0) {
+ return -ENODEV;
+ }
+
+ uint32_t modelId;
+ {
+ AutoMutex lock(mLock);
+ do {
+ modelId = nextUniqueId();
+ ALOGI("loadSoundModel modelId %u", modelId);
+ sp<SoundModel> model = mSoundModels.valueFor(modelId);
+ ALOGI("loadSoundModel model %p", model.get());
+ } while (mSoundModels.valueFor(modelId) != 0 && modelId != 0);
+ }
+ LOG_ALWAYS_FATAL_IF(modelId == 0,
+ "loadSoundModel(): wrap around in sound model IDs, num loaded models %zd",
+ mSoundModels.size());
+
+ ISoundTriggerHw::SoundModel *halSoundModel =
+ convertSoundModelToHal(sound_model);
+ if (halSoundModel == NULL) {
+ return -EINVAL;
+ }
+
+ Return<void> hidlReturn;
+ int32_t halReturn;
+ SoundModelHandle halHandle;
+ {
+ AutoMutex lock(mHalLock);
+ if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ hidlReturn = soundtrigger->loadPhraseSoundModel(
+ *(const ISoundTriggerHw::PhraseSoundModel *)halSoundModel,
+ this, modelId, [&](int32_t retval, auto res) {
+ halReturn = retval;
+ halHandle = res;
+ });
+
+ } else {
+ hidlReturn = soundtrigger->loadSoundModel(*halSoundModel,
+ this, modelId, [&](int32_t retval, auto res) {
+ halReturn = retval;
+ halHandle = res;
+ });
+ }
+ }
+
+ delete halSoundModel;
+
+ int ret = 0;
+ if (hidlReturn.getStatus().isOk()) {
+ AutoMutex lock(mLock);
+ *handle = (sound_model_handle_t)modelId;
+ sp<SoundModel> model = new SoundModel(*handle, callback, cookie, halHandle);
+ mSoundModels.add(*handle, model);
+ } else {
+ ret = (int)hidlReturn.getStatus().transactionError();
+ ALOGE("loadSoundModel error %d", ret);
+ if (ret == -EPIPE) {
+ clearService();
+ }
+ }
+
+
+ return ret;
+}
+
+int SoundTriggerHalHidl::unloadSoundModel(sound_model_handle_t handle)
+{
+ sp<ISoundTriggerHw> soundtrigger = getService();
+ if (soundtrigger == 0) {
+ return -ENODEV;
+ }
+
+ sp<SoundModel> model = removeModel(handle);
+ if (model == 0) {
+ ALOGE("unloadSoundModel model not found for handle %u", handle);
+ return -EINVAL;
+ }
+
+ Return<int32_t> halReturn(0);
+ {
+ AutoMutex lock(mHalLock);
+ halReturn = soundtrigger->unloadSoundModel(model->mHalHandle);
+ }
+
+ int ret = (int)halReturn.getStatus().transactionError();
+ ALOGE_IF(ret != 0, "unloadSoundModel error %d", ret);
+ if (ret == -EPIPE) {
+ clearService();
+ }
+
+ return ret;
+}
+
+int SoundTriggerHalHidl::startRecognition(sound_model_handle_t handle,
+ const struct sound_trigger_recognition_config *config,
+ recognition_callback_t callback,
+ void *cookie)
+{
+ sp<ISoundTriggerHw> soundtrigger = getService();
+ if (soundtrigger == 0) {
+ return -ENODEV;
+ }
+
+ sp<SoundModel> model = getModel(handle);
+ if (model == 0) {
+ ALOGE("startRecognition model not found for handle %u", handle);
+ return -EINVAL;
+ }
+
+ model->mRecognitionCallback = callback;
+ model->mRecognitionCookie = cookie;
+
+ ISoundTriggerHw::RecognitionConfig *halConfig =
+ convertRecognitionConfigToHal(config);
+
+ Return<int32_t> halReturn(0);
+ {
+ AutoMutex lock(mHalLock);
+ halReturn = soundtrigger->startRecognition(model->mHalHandle, *halConfig, this, handle);
+ }
+
+ delete halConfig;
+
+ int ret = (int)halReturn.getStatus().transactionError();
+ ALOGE_IF(ret != 0, "startRecognition error %d", ret);
+ if (ret == -EPIPE) {
+ clearService();
+ }
+ return ret;
+}
+
+int SoundTriggerHalHidl::stopRecognition(sound_model_handle_t handle)
+{
+ sp<ISoundTriggerHw> soundtrigger = getService();
+ if (soundtrigger == 0) {
+ return -ENODEV;
+ }
+
+ sp<SoundModel> model = getModel(handle);
+ if (model == 0) {
+ ALOGE("stopRecognition model not found for handle %u", handle);
+ return -EINVAL;
+ }
+
+ Return<int32_t> halReturn(0);
+ {
+ AutoMutex lock(mHalLock);
+ halReturn = soundtrigger->stopRecognition(model->mHalHandle);
+ }
+
+ int ret = (int)halReturn.getStatus().transactionError();
+ ALOGE_IF(ret != 0, "stopRecognition error %d", ret);
+ if (ret == -EPIPE) {
+ clearService();
+ }
+ return ret;
+}
+
+int SoundTriggerHalHidl::stopAllRecognitions()
+{
+ sp<ISoundTriggerHw> soundtrigger = getService();
+ if (soundtrigger == 0) {
+ return -ENODEV;
+ }
+
+ Return<int32_t> halReturn(0);
+ {
+ AutoMutex lock(mHalLock);
+ Return<int32_t> halReturn = soundtrigger->stopAllRecognitions();
+ }
+
+ int ret = (int)halReturn.getStatus().transactionError();
+ ALOGE_IF(ret != 0, "stopAllRecognitions error %d", ret);
+ if (ret == -EPIPE) {
+ clearService();
+ }
+ return ret;
+}
+
+SoundTriggerHalHidl::SoundTriggerHalHidl(const char *moduleName)
+ : mModuleName(moduleName), mNextUniqueId(1)
+{
+}
+
+void SoundTriggerHalHidl::onFirstRef()
+{
+ pthread_once(&sOnceControl, &sOnceInit);
+}
+
+SoundTriggerHalHidl::~SoundTriggerHalHidl()
+{
+}
+
+sp<ISoundTriggerHw> SoundTriggerHalHidl::getService()
+{
+ AutoMutex lock(mLock);
+ if (mISoundTrigger == 0) {
+ if (mModuleName == NULL) {
+ mModuleName = "primary";
+ }
+ std::string serviceName = "sound_trigger.";
+ serviceName.append(mModuleName);
+ mISoundTrigger = ISoundTriggerHw::getService(serviceName);
+ }
+ return mISoundTrigger;
+}
+
+void SoundTriggerHalHidl::clearService()
+{
+ AutoMutex lock(mLock);
+ mISoundTrigger = 0;
+}
+
+sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::getModel(sound_model_handle_t handle)
+{
+ AutoMutex lock(mLock);
+ return mSoundModels.valueFor(handle);
+}
+
+sp<SoundTriggerHalHidl::SoundModel> SoundTriggerHalHidl::removeModel(sound_model_handle_t handle)
+{
+ AutoMutex lock(mLock);
+ sp<SoundModel> model = mSoundModels.valueFor(handle);
+ mSoundModels.removeItem(handle);
+ return model;
+}
+
+uint32_t SoundTriggerHalHidl::nextUniqueId()
+{
+ return (uint32_t) atomic_fetch_add_explicit(&mNextUniqueId,
+ (uint_fast32_t) 1, memory_order_acq_rel);
+}
+
+void SoundTriggerHalHidl::convertUuidToHal(Uuid *halUuid,
+ const sound_trigger_uuid_t *uuid)
+{
+ halUuid->timeLow = uuid->timeLow;
+ halUuid->timeMid = uuid->timeMid;
+ halUuid->versionAndTimeHigh = uuid->timeHiAndVersion;
+ halUuid->variantAndClockSeqHigh = uuid->clockSeq;
+ memcpy(halUuid->node.data(), &uuid->node[0], sizeof(uuid->node));
+}
+
+void SoundTriggerHalHidl::convertUuidFromHal(sound_trigger_uuid_t *uuid,
+ const Uuid *halUuid)
+{
+ uuid->timeLow = halUuid->timeLow;
+ uuid->timeMid = halUuid->timeMid;
+ uuid->timeHiAndVersion = halUuid->versionAndTimeHigh;
+ uuid->clockSeq = halUuid->variantAndClockSeqHigh;
+ memcpy(&uuid->node[0], halUuid->node.data(), sizeof(uuid->node));
+}
+
+void SoundTriggerHalHidl::convertPropertiesFromHal(
+ struct sound_trigger_properties *properties,
+ const ISoundTriggerHw::Properties *halProperties)
+{
+ strlcpy(properties->implementor,
+ halProperties->implementor.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+ strlcpy(properties->description,
+ halProperties->description.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+ properties->version = halProperties->version;
+ convertUuidFromHal(&properties->uuid, &halProperties->uuid);
+ properties->max_sound_models = halProperties->maxSoundModels;
+ properties->max_key_phrases = halProperties->maxKeyPhrases;
+ properties->max_users = halProperties->maxUsers;
+ properties->recognition_modes = halProperties->recognitionModes;
+ properties->capture_transition = (bool)halProperties->captureTransition;
+ properties->max_buffer_ms = halProperties->maxBufferMs;
+ properties->concurrent_capture = (bool)halProperties->concurrentCapture;
+ properties->trigger_in_event = (bool)halProperties->triggerInEvent;
+ properties->power_consumption_mw = halProperties->powerConsumptionMw;
+}
+
+void SoundTriggerHalHidl::convertTriggerPhraseToHal(
+ ISoundTriggerHw::Phrase *halTriggerPhrase,
+ const struct sound_trigger_phrase *triggerPhrase)
+{
+ halTriggerPhrase->id = triggerPhrase->id;
+ halTriggerPhrase->recognitionModes = triggerPhrase->recognition_mode;
+ halTriggerPhrase->users.setToExternal((uint32_t *)&triggerPhrase->users[0], triggerPhrase->num_users);
+ halTriggerPhrase->locale = triggerPhrase->locale;
+ halTriggerPhrase->text = triggerPhrase->text;
+}
+
+ISoundTriggerHw::SoundModel *SoundTriggerHalHidl::convertSoundModelToHal(
+ const struct sound_trigger_sound_model *soundModel)
+{
+ ISoundTriggerHw::SoundModel *halModel = NULL;
+ if (soundModel->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+ ISoundTriggerHw::PhraseSoundModel *halKeyPhraseModel =
+ new ISoundTriggerHw::PhraseSoundModel();
+ struct sound_trigger_phrase_sound_model *keyPhraseModel =
+ (struct sound_trigger_phrase_sound_model *)soundModel;
+ ISoundTriggerHw::Phrase *halPhrases =
+ new ISoundTriggerHw::Phrase[keyPhraseModel->num_phrases];
+
+
+ for (unsigned int i = 0; i < keyPhraseModel->num_phrases; i++) {
+ convertTriggerPhraseToHal(&halPhrases[i],
+ &keyPhraseModel->phrases[i]);
+ }
+ halKeyPhraseModel->phrases.setToExternal(halPhrases, keyPhraseModel->num_phrases);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ halKeyPhraseModel->phrases.resize(keyPhraseModel->num_phrases);
+
+ delete[] halPhrases;
+
+ halModel = (ISoundTriggerHw::SoundModel *)halKeyPhraseModel;
+ } else {
+ halModel = new ISoundTriggerHw::SoundModel();
+ }
+ halModel->type = (SoundModelType)soundModel->type;
+ convertUuidToHal(&halModel->uuid, &soundModel->uuid);
+ convertUuidToHal(&halModel->vendorUuid, &soundModel->vendor_uuid);
+ halModel->data.setToExternal((uint8_t *)soundModel + soundModel->data_offset, soundModel->data_size);
+ halModel->data.resize(soundModel->data_size);
+
+ return halModel;
+}
+
+void SoundTriggerHalHidl::convertPhraseRecognitionExtraToHal(
+ PhraseRecognitionExtra *halExtra,
+ const struct sound_trigger_phrase_recognition_extra *extra)
+{
+ halExtra->id = extra->id;
+ halExtra->recognitionModes = extra->recognition_modes;
+ halExtra->confidenceLevel = extra->confidence_level;
+ ConfidenceLevel *halLevels =
+ new ConfidenceLevel[extra->num_levels];
+ for (unsigned int i = 0; i < extra->num_levels; i++) {
+ halLevels[i].userId = extra->levels[i].user_id;
+ halLevels[i].levelPercent = extra->levels[i].level;
+ }
+ halExtra->levels.setToExternal(halLevels, extra->num_levels);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ halExtra->levels.resize(extra->num_levels);
+
+ delete[] halLevels;
+}
+
+
+ISoundTriggerHw::RecognitionConfig *SoundTriggerHalHidl::convertRecognitionConfigToHal(
+ const struct sound_trigger_recognition_config *config)
+{
+ ISoundTriggerHw::RecognitionConfig *halConfig =
+ new ISoundTriggerHw::RecognitionConfig();
+
+ halConfig->captureHandle = config->capture_handle;
+ halConfig->captureDevice = (AudioDevice)config->capture_device;
+ halConfig->captureRequested = (uint32_t)config->capture_requested;
+
+ PhraseRecognitionExtra *halExtras =
+ new PhraseRecognitionExtra[config->num_phrases];
+
+ for (unsigned int i = 0; i < config->num_phrases; i++) {
+ convertPhraseRecognitionExtraToHal(&halExtras[i],
+ &config->phrases[i]);
+ }
+ halConfig->phrases.setToExternal(halExtras, config->num_phrases);
+ // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
+ halConfig->phrases.resize(config->num_phrases);
+
+ delete[] halExtras;
+
+ halConfig->data.setToExternal((uint8_t *)config + config->data_offset, config->data_size);
+
+ return halConfig;
+}
+
+
+// ISoundTriggerHwCallback
+::android::hardware::Return<void> SoundTriggerHalHidl::recognitionCallback(
+ const ISoundTriggerHwCallback::RecognitionEvent& halEvent,
+ CallbackCookie cookie)
+{
+ sp<SoundModel> model;
+ {
+ AutoMutex lock(mLock);
+ model = mSoundModels.valueFor((SoundModelHandle)cookie);
+ if (model == 0) {
+ return Return<void>();
+ }
+ }
+ struct sound_trigger_recognition_event *event = convertRecognitionEventFromHal(&halEvent);
+ if (event == NULL) {
+ return Return<void>();
+ }
+ event->model = model->mHandle;
+ model->mRecognitionCallback(event, model->mRecognitionCookie);
+
+ free(event);
+
+ return Return<void>();
+}
+
+::android::hardware::Return<void> SoundTriggerHalHidl::phraseRecognitionCallback(
+ const ISoundTriggerHwCallback::PhraseRecognitionEvent& halEvent,
+ CallbackCookie cookie)
+{
+ sp<SoundModel> model;
+ {
+ AutoMutex lock(mLock);
+ model = mSoundModels.valueFor((SoundModelHandle)cookie);
+ if (model == 0) {
+ return Return<void>();
+ }
+ }
+
+ struct sound_trigger_recognition_event *event = convertRecognitionEventFromHal(
+ (const ISoundTriggerHwCallback::RecognitionEvent *)&halEvent);
+ if (event == NULL) {
+ return Return<void>();
+ }
+
+ event->model = model->mHandle;
+ model->mRecognitionCallback(event, model->mRecognitionCookie);
+
+ free(event);
+
+ return Return<void>();
+}
+
+::android::hardware::Return<void> SoundTriggerHalHidl::soundModelCallback(
+ const ISoundTriggerHwCallback::ModelEvent& halEvent,
+ CallbackCookie cookie)
+{
+ sp<SoundModel> model;
+ {
+ AutoMutex lock(mLock);
+ model = mSoundModels.valueFor((SoundModelHandle)cookie);
+ if (model == 0) {
+ return Return<void>();
+ }
+ }
+
+ struct sound_trigger_model_event *event = convertSoundModelEventFromHal(&halEvent);
+ if (event == NULL) {
+ return Return<void>();
+ }
+
+ event->model = model->mHandle;
+ model->mSoundModelCallback(event, model->mSoundModelCookie);
+
+ free(event);
+
+ return Return<void>();
+}
+
+
+struct sound_trigger_model_event *SoundTriggerHalHidl::convertSoundModelEventFromHal(
+ const ISoundTriggerHwCallback::ModelEvent *halEvent)
+{
+ struct sound_trigger_model_event *event = (struct sound_trigger_model_event *)malloc(
+ sizeof(struct sound_trigger_model_event) +
+ halEvent->data.size());
+ if (event == NULL) {
+ return NULL;
+ }
+
+ event->status = (int)halEvent->status;
+ // event->model to be set by caller
+ event->data_offset = sizeof(struct sound_trigger_model_event);
+ event->data_size = halEvent->data.size();
+ uint8_t *dst = (uint8_t *)event + event->data_offset;
+ uint8_t *src = (uint8_t *)&halEvent->data[0];
+ memcpy(dst, src, halEvent->data.size());
+
+ return event;
+}
+
+void SoundTriggerHalHidl::convertPhraseRecognitionExtraFromHal(
+ struct sound_trigger_phrase_recognition_extra *extra,
+ const PhraseRecognitionExtra *halExtra)
+{
+ extra->id = halExtra->id;
+ extra->recognition_modes = halExtra->recognitionModes;
+ extra->confidence_level = halExtra->confidenceLevel;
+
+ size_t i;
+ for (i = 0; i < halExtra->levels.size() && i < SOUND_TRIGGER_MAX_USERS; i++) {
+ extra->levels[i].user_id = halExtra->levels[i].userId;
+ extra->levels[i].level = halExtra->levels[i].levelPercent;
+ }
+ extra->num_levels = (unsigned int)i;
+}
+
+
+struct sound_trigger_recognition_event *SoundTriggerHalHidl::convertRecognitionEventFromHal(
+ const ISoundTriggerHwCallback::RecognitionEvent *halEvent)
+{
+ struct sound_trigger_recognition_event *event;
+
+ if (halEvent->type == SoundModelType::KEYPHRASE) {
+ struct sound_trigger_phrase_recognition_event *phraseEvent =
+ (struct sound_trigger_phrase_recognition_event *)malloc(
+ sizeof(struct sound_trigger_phrase_recognition_event) +
+ halEvent->data.size());
+ if (phraseEvent == NULL) {
+ return NULL;
+ }
+ const ISoundTriggerHwCallback::PhraseRecognitionEvent *halPhraseEvent =
+ (const ISoundTriggerHwCallback::PhraseRecognitionEvent *)halEvent;
+
+ for (unsigned int i = 0; i < halPhraseEvent->phraseExtras.size(); i++) {
+ convertPhraseRecognitionExtraFromHal(&phraseEvent->phrase_extras[i],
+ &halPhraseEvent->phraseExtras[i]);
+ }
+ phraseEvent->num_phrases = halPhraseEvent->phraseExtras.size();
+ event = (struct sound_trigger_recognition_event *)phraseEvent;
+ event->data_offset = sizeof(sound_trigger_phrase_recognition_event);
+ } else {
+ event = (struct sound_trigger_recognition_event *)malloc(
+ sizeof(struct sound_trigger_recognition_event) + halEvent->data.size());
+ if (event == NULL) {
+ return NULL;
+ }
+ event->data_offset = sizeof(sound_trigger_recognition_event);
+ }
+ event->status = (int)halEvent->status;
+ event->type = (sound_trigger_sound_model_type_t)halEvent->type;
+ // event->model to be set by caller
+ event->capture_available = (bool)halEvent->captureAvailable;
+ event->capture_session = halEvent->captureSession;
+ event->capture_delay_ms = halEvent->captureDelayMs;
+ event->capture_preamble_ms = halEvent->capturePreambleMs;
+ event->trigger_in_data = (bool)halEvent->triggerInData;
+ event->audio_config.sample_rate = halEvent->audioConfig.sampleRateHz;
+ event->audio_config.channel_mask = (audio_channel_mask_t)halEvent->audioConfig.channelMask;
+ event->audio_config.format = (audio_format_t)halEvent->audioConfig.format;
+
+ event->data_size = halEvent->data.size();
+ uint8_t *dst = (uint8_t *)event + event->data_offset;
+ uint8_t *src = (uint8_t *)&halEvent->data[0];
+ memcpy(dst, src, halEvent->data.size());
+
+ return event;
+}
+
+} // namespace android
diff --git a/services/soundtrigger/SoundTriggerHalHidl.h b/services/soundtrigger/SoundTriggerHalHidl.h
new file mode 100644
index 0000000..60404dc
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalHidl.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_HIDL_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_HIDL_H
+
+#include <utils/RefBase.h>
+#include <utils/KeyedVector.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+#include "SoundTriggerHalInterface.h"
+#include <android/hardware/soundtrigger/2.0/types.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
+#include <android/hardware/soundtrigger/2.0/BnSoundTriggerHwCallback.h>
+
+namespace android {
+
+using android::hardware::audio::common::V2_0::Uuid;
+using android::hardware::soundtrigger::V2_0::ConfidenceLevel;
+using android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra;
+using android::hardware::soundtrigger::V2_0::SoundModelType;
+using android::hardware::soundtrigger::V2_0::SoundModelHandle;
+using android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
+using android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+
+class SoundTriggerHalHidl : public SoundTriggerHalInterface,
+ public virtual ISoundTriggerHwCallback
+
+{
+public:
+ virtual int getProperties(struct sound_trigger_properties *properties);
+
+ /*
+ * Load a sound model. Once loaded, recognition of this model can be started and stopped.
+ * Only one active recognition per model at a time. The SoundTrigger service will handle
+ * concurrent recognition requests by different users/applications on the same model.
+ * The implementation returns a unique handle used by other functions (unload_sound_model(),
+ * start_recognition(), etc...
+ */
+ virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
+ sound_model_callback_t callback,
+ void *cookie,
+ sound_model_handle_t *handle);
+
+ /*
+ * Unload a sound model. A sound model can be unloaded to make room for a new one to overcome
+ * implementation limitations.
+ */
+ virtual int unloadSoundModel(sound_model_handle_t handle);
+
+ /* Start recognition on a given model. Only one recognition active at a time per model.
+ * Once recognition succeeds of fails, the callback is called.
+ * TODO: group recognition configuration parameters into one struct and add key phrase options.
+ */
+ virtual int startRecognition(sound_model_handle_t handle,
+ const struct sound_trigger_recognition_config *config,
+ recognition_callback_t callback,
+ void *cookie);
+
+ /* Stop recognition on a given model.
+ * The implementation does not have to call the callback when stopped via this method.
+ */
+ virtual int stopRecognition(sound_model_handle_t handle);
+
+ /* Stop recognition on all models.
+ * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_1 or above.
+ * If no implementation is provided, stop_recognition will be called for each running model.
+ */
+ virtual int stopAllRecognitions();
+
+ // RefBase
+ virtual void onFirstRef();
+
+ // ISoundTriggerHwCallback
+ virtual ::android::hardware::Return<void> recognitionCallback(
+ const ISoundTriggerHwCallback::RecognitionEvent& event, CallbackCookie cookie);
+ virtual ::android::hardware::Return<void> phraseRecognitionCallback(
+ const ISoundTriggerHwCallback::PhraseRecognitionEvent& event, int32_t cookie);
+ virtual ::android::hardware::Return<void> soundModelCallback(
+ const ISoundTriggerHwCallback::ModelEvent& event, CallbackCookie cookie);
+private:
+ class SoundModel : public RefBase {
+ public:
+ SoundModel(sound_model_handle_t handle, sound_model_callback_t callback,
+ void *cookie, android::hardware::soundtrigger::V2_0::SoundModelHandle halHandle)
+ : mHandle(handle), mHalHandle(halHandle),
+ mSoundModelCallback(callback), mSoundModelCookie(cookie),
+ mRecognitionCallback(NULL), mRecognitionCookie(NULL) {}
+ ~SoundModel() {}
+
+ sound_model_handle_t mHandle;
+ android::hardware::soundtrigger::V2_0::SoundModelHandle mHalHandle;
+ sound_model_callback_t mSoundModelCallback;
+ void * mSoundModelCookie;
+ recognition_callback_t mRecognitionCallback;
+ void * mRecognitionCookie;
+ };
+
+ friend class SoundTriggerHalInterface;
+
+ explicit SoundTriggerHalHidl(const char *moduleName = NULL);
+ virtual ~SoundTriggerHalHidl();
+
+ void convertUuidToHal(Uuid *halUuid,
+ const sound_trigger_uuid_t *uuid);
+ void convertUuidFromHal(sound_trigger_uuid_t *uuid,
+ const Uuid *halUuid);
+
+ void convertPropertiesFromHal(
+ struct sound_trigger_properties *properties,
+ const ISoundTriggerHw::Properties *halProperties);
+
+ void convertTriggerPhraseToHal(
+ ISoundTriggerHw::Phrase *halTriggerPhrase,
+ const struct sound_trigger_phrase *triggerPhrase);
+ ISoundTriggerHw::SoundModel *convertSoundModelToHal(
+ const struct sound_trigger_sound_model *soundModel);
+
+ void convertPhraseRecognitionExtraToHal(
+ PhraseRecognitionExtra *halExtra,
+ const struct sound_trigger_phrase_recognition_extra *extra);
+ ISoundTriggerHw::RecognitionConfig *convertRecognitionConfigToHal(
+ const struct sound_trigger_recognition_config *config);
+
+ struct sound_trigger_model_event *convertSoundModelEventFromHal(
+ const ISoundTriggerHwCallback::ModelEvent *halEvent);
+ void convertPhraseRecognitionExtraFromHal(
+ struct sound_trigger_phrase_recognition_extra *extra,
+ const PhraseRecognitionExtra *halExtra);
+ struct sound_trigger_recognition_event *convertRecognitionEventFromHal(
+ const ISoundTriggerHwCallback::RecognitionEvent *halEvent);
+
+ uint32_t nextUniqueId();
+ sp<ISoundTriggerHw> getService();
+ void clearService();
+ sp<SoundModel> getModel(sound_model_handle_t handle);
+ sp<SoundModel> removeModel(sound_model_handle_t handle);
+
+ static pthread_once_t sOnceControl;
+ static void sOnceInit();
+
+ Mutex mLock;
+ Mutex mHalLock;
+ const char *mModuleName;
+ volatile atomic_uint_fast32_t mNextUniqueId;
+ // Effect chains without a valid thread
+ DefaultKeyedVector< sound_model_handle_t , sp<SoundModel> > mSoundModels;
+ sp<::android::hardware::soundtrigger::V2_0::ISoundTriggerHw> mISoundTrigger;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_HIDL_H
diff --git a/services/soundtrigger/SoundTriggerHalInterface.h b/services/soundtrigger/SoundTriggerHalInterface.h
new file mode 100644
index 0000000..c083195
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalInterface.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_INTERFACE_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_INTERFACE_H
+
+#include <utils/RefBase.h>
+#include <system/sound_trigger.h>
+#include <hardware/sound_trigger.h>
+
+namespace android {
+
+class SoundTriggerHalInterface : public virtual RefBase
+{
+public:
+ /* get a sound trigger HAL instance */
+ static sp<SoundTriggerHalInterface> connectModule(const char *moduleName);
+
+ virtual ~SoundTriggerHalInterface() {}
+
+ virtual int getProperties(struct sound_trigger_properties *properties) = 0;
+
+ /*
+ * Load a sound model. Once loaded, recognition of this model can be started and stopped.
+ * Only one active recognition per model at a time. The SoundTrigger service will handle
+ * concurrent recognition requests by different users/applications on the same model.
+ * The implementation returns a unique handle used by other functions (unload_sound_model(),
+ * start_recognition(), etc...
+ */
+ virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
+ sound_model_callback_t callback,
+ void *cookie,
+ sound_model_handle_t *handle) = 0;
+
+ /*
+ * Unload a sound model. A sound model can be unloaded to make room for a new one to overcome
+ * implementation limitations.
+ */
+ virtual int unloadSoundModel(sound_model_handle_t handle) = 0;
+
+ /* Start recognition on a given model. Only one recognition active at a time per model.
+ * Once recognition succeeds of fails, the callback is called.
+ * TODO: group recognition configuration parameters into one struct and add key phrase options.
+ */
+ virtual int startRecognition(sound_model_handle_t handle,
+ const struct sound_trigger_recognition_config *config,
+ recognition_callback_t callback,
+ void *cookie) = 0;
+
+ /* Stop recognition on a given model.
+ * The implementation does not have to call the callback when stopped via this method.
+ */
+ virtual int stopRecognition(sound_model_handle_t handle) = 0;
+
+ /* Stop recognition on all models.
+ * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_1 or above.
+ * If no implementation is provided, stop_recognition will be called for each running model.
+ */
+ virtual int stopAllRecognitions() = 0;
+
+protected:
+ SoundTriggerHalInterface() {}
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_INTERFACE_H
diff --git a/services/soundtrigger/SoundTriggerHalLegacy.cpp b/services/soundtrigger/SoundTriggerHalLegacy.cpp
new file mode 100644
index 0000000..2b78818
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalLegacy.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/Log.h>
+#include "SoundTriggerHalLegacy.h"
+
+namespace android {
+
+/* static */
+sp<SoundTriggerHalInterface> SoundTriggerHalInterface::connectModule(const char *moduleName)
+{
+ return new SoundTriggerHalLegacy(moduleName);
+}
+
+SoundTriggerHalLegacy::SoundTriggerHalLegacy(const char *moduleName)
+ : mModuleName(moduleName), mHwDevice(NULL)
+{
+}
+
+void SoundTriggerHalLegacy::onFirstRef()
+{
+ const hw_module_t *mod;
+ int rc;
+
+ if (mModuleName == NULL) {
+ mModuleName = "primary";
+ }
+
+ rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
+ if (rc != 0) {
+ ALOGE("couldn't load sound trigger module %s.%s (%s)",
+ SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+ return;
+ }
+ rc = sound_trigger_hw_device_open(mod, &mHwDevice);
+ if (rc != 0) {
+ ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
+ SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+ mHwDevice = NULL;
+ return;
+ }
+ if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
+ mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
+ ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
+ return;
+ }
+}
+
+SoundTriggerHalLegacy::~SoundTriggerHalLegacy()
+{
+ if (mHwDevice != NULL) {
+ sound_trigger_hw_device_close(mHwDevice);
+ }
+}
+
+int SoundTriggerHalLegacy::getProperties(struct sound_trigger_properties *properties)
+{
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ return mHwDevice->get_properties(mHwDevice, properties);
+}
+
+int SoundTriggerHalLegacy::loadSoundModel(struct sound_trigger_sound_model *sound_model,
+ sound_model_callback_t callback,
+ void *cookie,
+ sound_model_handle_t *handle)
+{
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ return mHwDevice->load_sound_model(mHwDevice, sound_model, callback, cookie, handle);
+}
+
+int SoundTriggerHalLegacy::unloadSoundModel(sound_model_handle_t handle)
+{
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ return mHwDevice->unload_sound_model(mHwDevice, handle);
+}
+
+int SoundTriggerHalLegacy::startRecognition(sound_model_handle_t handle,
+ const struct sound_trigger_recognition_config *config,
+ recognition_callback_t callback,
+ void *cookie)
+{
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ return mHwDevice->start_recognition(mHwDevice, handle, config, callback, cookie);
+}
+
+int SoundTriggerHalLegacy::stopRecognition(sound_model_handle_t handle)
+{
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ return mHwDevice->stop_recognition(mHwDevice, handle);
+}
+
+int SoundTriggerHalLegacy::stopAllRecognitions()
+{
+ if (mHwDevice == NULL) {
+ return -ENODEV;
+ }
+ if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
+ mHwDevice->stop_all_recognitions) {
+ return mHwDevice->stop_all_recognitions(mHwDevice);
+ }
+ return -ENOSYS;
+}
+
+} // namespace android
diff --git a/services/soundtrigger/SoundTriggerHalLegacy.h b/services/soundtrigger/SoundTriggerHalLegacy.h
new file mode 100644
index 0000000..52488de
--- /dev/null
+++ b/services/soundtrigger/SoundTriggerHalLegacy.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_LEGACY_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_LEGACY_H
+
+#include "SoundTriggerHalInterface.h"
+
+namespace android {
+
+class SoundTriggerHalLegacy : public SoundTriggerHalInterface
+
+{
+public:
+ virtual ~SoundTriggerHalLegacy();
+
+ virtual int getProperties(struct sound_trigger_properties *properties);
+
+ /*
+ * Load a sound model. Once loaded, recognition of this model can be started and stopped.
+ * Only one active recognition per model at a time. The SoundTrigger service will handle
+ * concurrent recognition requests by different users/applications on the same model.
+ * The implementation returns a unique handle used by other functions (unload_sound_model(),
+ * start_recognition(), etc...
+ */
+ virtual int loadSoundModel(struct sound_trigger_sound_model *sound_model,
+ sound_model_callback_t callback,
+ void *cookie,
+ sound_model_handle_t *handle);
+
+ /*
+ * Unload a sound model. A sound model can be unloaded to make room for a new one to overcome
+ * implementation limitations.
+ */
+ virtual int unloadSoundModel(sound_model_handle_t handle);
+
+ /* Start recognition on a given model. Only one recognition active at a time per model.
+ * Once recognition succeeds of fails, the callback is called.
+ * TODO: group recognition configuration parameters into one struct and add key phrase options.
+ */
+ virtual int startRecognition(sound_model_handle_t handle,
+ const struct sound_trigger_recognition_config *config,
+ recognition_callback_t callback,
+ void *cookie);
+
+ /* Stop recognition on a given model.
+ * The implementation does not have to call the callback when stopped via this method.
+ */
+ virtual int stopRecognition(sound_model_handle_t handle);
+
+ /* Stop recognition on all models.
+ * Only supported for device api versions SOUND_TRIGGER_DEVICE_API_VERSION_1_1 or above.
+ * If no implementation is provided, stop_recognition will be called for each running model.
+ */
+ int stopAllRecognitions();
+
+ // RefBase
+ virtual void onFirstRef();
+
+private:
+
+ friend class SoundTriggerHalInterface;
+
+ explicit SoundTriggerHalLegacy(const char *moduleName = NULL);
+
+ const char *mModuleName;
+ struct sound_trigger_hw_device* mHwDevice;
+};
+
+} // namespace android
+
+#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_LEGACY_H
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 6a52b9c..3ba7f62 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -32,17 +32,16 @@
#include <binder/IServiceManager.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
-#include <hardware/sound_trigger.h>
+#include <system/sound_trigger.h>
#include <ServiceUtilities.h>
#include "SoundTriggerHwService.h"
-namespace android {
-
#ifdef SOUND_TRIGGER_USE_STUB_MODULE
#define HW_MODULE_PREFIX "stub"
#else
#define HW_MODULE_PREFIX "primary"
#endif
+namespace android {
SoundTriggerHwService::SoundTriggerHwService()
: BnSoundTriggerHwService(),
@@ -54,30 +53,17 @@
void SoundTriggerHwService::onFirstRef()
{
- const hw_module_t *mod;
int rc;
- sound_trigger_hw_device *dev;
- rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod);
- if (rc != 0) {
- ALOGE("couldn't load sound trigger module %s.%s (%s)",
- SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
- return;
- }
- rc = sound_trigger_hw_device_open(mod, &dev);
- if (rc != 0) {
- ALOGE("couldn't open sound trigger hw device in %s.%s (%s)",
- SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, strerror(-rc));
- return;
- }
- if (dev->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
- dev->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
- ALOGE("wrong sound trigger hw device version %04x", dev->common.version);
- return;
- }
+ sp<SoundTriggerHalInterface> halInterface =
+ SoundTriggerHalInterface::connectModule(HW_MODULE_PREFIX);
+ if (halInterface == 0) {
+ ALOGW("could not connect to HAL");
+ return;
+ }
sound_trigger_module_descriptor descriptor;
- rc = dev->get_properties(dev, &descriptor.properties);
+ rc = halInterface->getProperties(&descriptor.properties);
if (rc != 0) {
ALOGE("could not read implementation properties");
return;
@@ -88,7 +74,7 @@
descriptor.handle);
sp<ISoundTriggerClient> client;
- sp<Module> module = new Module(this, dev, descriptor, client);
+ sp<Module> module = new Module(this, halInterface, descriptor, client);
mModules.add(descriptor.handle, module);
mCallbackThread = new CallbackThread(this);
}
@@ -98,9 +84,6 @@
if (mCallbackThread != 0) {
mCallbackThread->exit();
}
- for (size_t i = 0; i < mModules.size(); i++) {
- sound_trigger_hw_device_close(mModules.valueAt(i)->hwDevice());
- }
}
status_t SoundTriggerHwService::listModules(struct sound_trigger_module_descriptor *modules,
@@ -489,10 +472,10 @@
#define LOG_TAG "SoundTriggerHwService::Module"
SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service,
- sound_trigger_hw_device* hwDevice,
+ const sp<SoundTriggerHalInterface>& halInterface,
sound_trigger_module_descriptor descriptor,
const sp<ISoundTriggerClient>& client)
- : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor),
+ : mService(service), mHalInterface(halInterface), mDescriptor(descriptor),
mClient(client), mServiceState(SOUND_TRIGGER_STATE_NO_INIT)
{
}
@@ -510,10 +493,12 @@
for (size_t i = 0; i < mModels.size(); i++) {
sp<Model> model = mModels.valueAt(i);
ALOGV("detach() unloading model %d", model->mHandle);
- if (model->mState == Model::STATE_ACTIVE) {
- mHwDevice->stop_recognition(mHwDevice, model->mHandle);
+ if (mHalInterface != 0) {
+ if (model->mState == Model::STATE_ACTIVE) {
+ mHalInterface->stopRecognition(model->mHandle);
+ }
+ mHalInterface->unloadSoundModel(model->mHandle);
}
- mHwDevice->unload_sound_model(mHwDevice, model->mHandle);
}
mModels.clear();
}
@@ -531,10 +516,12 @@
sound_model_handle_t *handle)
{
ALOGV("loadSoundModel() handle");
+ if (mHalInterface == 0) {
+ return NO_INIT;
+ }
if (!captureHotwordAllowed()) {
return PERMISSION_DENIED;
}
-
if (modelMemory == 0 || modelMemory->pointer() == NULL) {
ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()");
return BAD_VALUE;
@@ -566,7 +553,7 @@
return INVALID_OPERATION;
}
- status_t status = mHwDevice->load_sound_model(mHwDevice, sound_model,
+ status_t status = mHalInterface->loadSoundModel(sound_model,
SoundTriggerHwService::soundModelCallback,
this, handle);
@@ -601,6 +588,9 @@
status_t SoundTriggerHwService::Module::unloadSoundModel_l(sound_model_handle_t handle)
{
+ if (mHalInterface == 0) {
+ return NO_INIT;
+ }
ssize_t index = mModels.indexOfKey(handle);
if (index < 0) {
return BAD_VALUE;
@@ -608,17 +598,20 @@
sp<Model> model = mModels.valueAt(index);
mModels.removeItem(handle);
if (model->mState == Model::STATE_ACTIVE) {
- mHwDevice->stop_recognition(mHwDevice, model->mHandle);
+ mHalInterface->stopRecognition(model->mHandle);
model->mState = Model::STATE_IDLE;
}
AudioSystem::releaseSoundTriggerSession(model->mCaptureSession);
- return mHwDevice->unload_sound_model(mHwDevice, handle);
+ return mHalInterface->unloadSoundModel(handle);
}
status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle,
const sp<IMemory>& dataMemory)
{
ALOGV("startRecognition() model handle %d", handle);
+ if (mHalInterface == 0) {
+ return NO_INIT;
+ }
if (!captureHotwordAllowed()) {
return PERMISSION_DENIED;
}
@@ -657,7 +650,7 @@
//TODO: get capture handle and device from audio policy service
config->capture_handle = model->mCaptureIOHandle;
config->capture_device = model->mCaptureDevice;
- status_t status = mHwDevice->start_recognition(mHwDevice, handle, config,
+ status_t status = mHalInterface->startRecognition(handle, config,
SoundTriggerHwService::recognitionCallback,
this);
@@ -672,6 +665,9 @@
status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle)
{
ALOGV("stopRecognition() model handle %d", handle);
+ if (mHalInterface == 0) {
+ return NO_INIT;
+ }
if (!captureHotwordAllowed()) {
return PERMISSION_DENIED;
}
@@ -685,7 +681,7 @@
if (model->mState != Model::STATE_ACTIVE) {
return INVALID_OPERATION;
}
- mHwDevice->stop_recognition(mHwDevice, handle);
+ mHalInterface->stopRecognition(handle);
model->mState = Model::STATE_IDLE;
return NO_ERROR;
}
@@ -808,18 +804,13 @@
}
const bool supports_stop_all =
- (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
- mHwDevice->stop_all_recognitions);
-
- if (supports_stop_all) {
- mHwDevice->stop_all_recognitions(mHwDevice);
- }
+ (mHalInterface != 0) && (mHalInterface->stopAllRecognitions() == ENOSYS);
for (size_t i = 0; i < mModels.size(); i++) {
sp<Model> model = mModels.valueAt(i);
if (model->mState == Model::STATE_ACTIVE) {
- if (!supports_stop_all) {
- mHwDevice->stop_recognition(mHwDevice, model->mHandle);
+ if (mHalInterface != 0 && !supports_stop_all) {
+ mHalInterface->stopRecognition(model->mHandle);
}
// keep model in ACTIVE state so that event is processed by onCallbackEvent()
if (model->mType == SOUND_MODEL_TYPE_KEYPHRASE) {
diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h
index 13a577a..7f7d0cc 100644
--- a/services/soundtrigger/SoundTriggerHwService.h
+++ b/services/soundtrigger/SoundTriggerHwService.h
@@ -26,7 +26,7 @@
#include <soundtrigger/ISoundTrigger.h>
#include <soundtrigger/ISoundTriggerClient.h>
#include <system/sound_trigger.h>
-#include <hardware/sound_trigger.h>
+#include "SoundTriggerHalInterface.h"
namespace android {
@@ -103,7 +103,7 @@
public:
Module(const sp<SoundTriggerHwService>& service,
- sound_trigger_hw_device* hwDevice,
+ const sp<SoundTriggerHalInterface>& halInterface,
sound_trigger_module_descriptor descriptor,
const sp<ISoundTriggerClient>& client);
@@ -123,7 +123,6 @@
virtual status_t dump(int fd, const Vector<String16>& args);
- sound_trigger_hw_device *hwDevice() const { return mHwDevice; }
struct sound_trigger_module_descriptor descriptor() { return mDescriptor; }
void setClient(const sp<ISoundTriggerClient>& client) { mClient = client; }
void clearClient() { mClient.clear(); }
@@ -146,7 +145,7 @@
Mutex mLock;
wp<SoundTriggerHwService> mService;
- struct sound_trigger_hw_device* mHwDevice;
+ sp<SoundTriggerHalInterface> mHalInterface;
struct sound_trigger_module_descriptor mDescriptor;
sp<ISoundTriggerClient> mClient;
DefaultKeyedVector< sound_model_handle_t, sp<Model> > mModels;