diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc index fea5a1d5c..9b637b212 100644 --- a/camera/cameraserver/cameraserver.rc +++ b/camera/cameraserver/cameraserver.rc @@ -3,4 +3,4 @@ service cameraserver /system/bin/cameraserver user cameraserver group audio camera input drmrpc ioprio rt 4 - writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks + writepid /dev/cpuset/camera-daemon/tasks /dev/stune/foreground/tasks diff --git a/include/media/IMediaExtractorService.h b/include/media/IMediaExtractorService.h index 4d7b317fc..a50fd74f6 100644 --- a/include/media/IMediaExtractorService.h +++ b/include/media/IMediaExtractorService.h @@ -30,7 +30,8 @@ class IMediaExtractorService: public IInterface public: DECLARE_META_INTERFACE(MediaExtractorService); - virtual sp makeExtractor(const sp &source, const char *mime) = 0; + virtual sp makeExtractor(const sp &source, const char *mime, + const uint32_t extFlags) = 0; }; diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h index c2e75a61c..07d016729 100644 --- a/include/media/stagefright/CameraSource.h +++ b/include/media/stagefright/CameraSource.h @@ -127,6 +127,8 @@ class CameraSource : public MediaSource, public MediaBufferObserver { virtual void signalBufferReturned(MediaBuffer* buffer); + virtual void notifyPerformanceMode() {} + protected: /** diff --git a/include/media/stagefright/ExtendedMediaDefs.h b/include/media/stagefright/ExtendedMediaDefs.h index 1e60fc1d4..6625795e3 100644 --- a/include/media/stagefright/ExtendedMediaDefs.h +++ b/include/media/stagefright/ExtendedMediaDefs.h @@ -66,7 +66,7 @@ extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4_DP; extern const char *MEDIA_MIMETYPE_AUDIO_DSD; extern const char *MEDIA_MIMETYPE_CONTAINER_DSF; extern const char *MEDIA_MIMETYPE_CONTAINER_DFF; - +extern const char *MEDIA_MIMETYPE_CONTAINER_MOV; } // namespace android diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h index 5932610ca..d2d9d84ab 100644 --- a/include/media/stagefright/MPEG4Writer.h +++ b/include/media/stagefright/MPEG4Writer.h @@ -225,6 +225,10 @@ class MPEG4Writer : public MediaWriter { static uint32_t getMpeg4Time(); + int64_t mLastAudioTimeStampUs; + void setLastAudioTimeStamp(int64_t ts) {mLastAudioTimeStampUs = ts;} + int64_t getLastAudioTimeStamp() {return mLastAudioTimeStampUs;} + MPEG4Writer(const MPEG4Writer &); MPEG4Writer &operator=(const MPEG4Writer &); }; diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h index 1044ee4d6..2020bbaa4 100644 --- a/include/media/stagefright/MediaCodecSource.h +++ b/include/media/stagefright/MediaCodecSource.h @@ -68,6 +68,8 @@ struct MediaCodecSource : public MediaSource, // for AHandlerReflector void onMessageReceived(const sp &msg); + void notifyPerformanceMode(); + protected: virtual ~MediaCodecSource(); @@ -145,6 +147,10 @@ struct MediaCodecSource : public MediaSource, int32_t mGeneration; + int64_t mPrevBufferTimestampUs; + bool mIsHFR; + int32_t mBatchSize; + DISALLOW_EVIL_CONSTRUCTORS(MediaCodecSource); }; diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h index 6bf8c9e3b..84feb6ba3 100644 --- a/include/media/stagefright/MediaExtractor.h +++ b/include/media/stagefright/MediaExtractor.h @@ -30,9 +30,11 @@ class MetaData; class MediaExtractor : public BnMediaExtractor { public: static sp Create( - const sp &source, const char *mime = NULL); + const sp &source, const char *mime = NULL, + const uint32_t flags = 0); static sp CreateFromService( - const sp &source, const char *mime = NULL); + const sp &source, const char *mime = NULL, + const uint32_t flags = 0); virtual size_t countTracks() = 0; virtual sp getTrack(size_t index) = 0; @@ -73,6 +75,8 @@ class MediaExtractor : public BnMediaExtractor { virtual const char * name() { return ""; } + virtual void setExtraFlags(uint32_t flags) {} + protected: MediaExtractor(); virtual ~MediaExtractor() {} diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk index 0947687c3..3d16a36d0 100644 --- a/media/audioserver/Android.mk +++ b/media/audioserver/Android.mk @@ -76,4 +76,10 @@ ifeq ($(strip $(DOLBY_ENABLE)),true) endif # DOLBY_END +ifeq ($(strip $(SPATIAL_AUDIO_ENABLED)), true) + LOCAL_CFLAGS += -DVRAUDIOSERVICE_ENABLE + LOCAL_C_INCLUDES += $(vr_audio_includes) + LOCAL_SHARED_LIBRARIES += libvraudio +endif + include $(BUILD_EXECUTABLE) diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp index 6a7f9cae8..a63cc7899 100644 --- a/media/audioserver/main_audioserver.cpp +++ b/media/audioserver/main_audioserver.cpp @@ -56,6 +56,10 @@ #include "DolbyMemoryService.h" #endif +#ifdef VRAUDIOSERVICE_ENABLE +#include "VRAudioService.h" +#endif + using namespace android; int main(int argc __unused, char **argv) @@ -154,6 +158,9 @@ int main(int argc __unused, char **argv) DolbyMemoryService::instantiate(); #endif SoundTriggerHwService::instantiate(); +#ifdef VRAUDIOSERVICE_ENABLE + VRAudioServiceNative::instantiate(); +#endif ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); } diff --git a/media/libavextensions/mediaplayerservice/AVNuExtensions.h b/media/libavextensions/mediaplayerservice/AVNuExtensions.h index 5bbeb8f64..93d524aa3 100644 --- a/media/libavextensions/mediaplayerservice/AVNuExtensions.h +++ b/media/libavextensions/mediaplayerservice/AVNuExtensions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -75,6 +75,7 @@ struct AVNuUtils { virtual audio_format_t getPCMFormat(const sp &); virtual void setCodecOutputFormat(const sp &); virtual bool isByteStreamModeEnabled(const sp &); + virtual uint32_t getFlags(); // ----- NO TRESSPASSING BEYOND THIS LINE ------ DECLARE_LOADABLE_SINGLETON(AVNuUtils); diff --git a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp index 322518254..f5674879c 100644 --- a/media/libavextensions/mediaplayerservice/AVNuUtils.cpp +++ b/media/libavextensions/mediaplayerservice/AVNuUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -103,6 +103,10 @@ bool AVNuUtils::isByteStreamModeEnabled(const sp &) { } #endif +uint32_t AVNuUtils::getFlags() { + return 0; +} + // ----- NO TRESSPASSING BEYOND THIS LINE ------ AVNuUtils::AVNuUtils() {} diff --git a/media/libavextensions/stagefright/AVExtensions.h b/media/libavextensions/stagefright/AVExtensions.h index e528a2ed4..8b8792eec 100644 --- a/media/libavextensions/stagefright/AVExtensions.h +++ b/media/libavextensions/stagefright/AVExtensions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -35,6 +35,7 @@ #include #include #include +#include #include "ESQueue.h" namespace android { @@ -60,7 +61,8 @@ struct AudioSource; struct AVFactory { virtual sp createACodec(); virtual MediaExtractor* createExtendedExtractor( - const sp &source, const char *mime, const sp &meta); + const sp &source, const char *mime, const sp &meta, + const uint32_t flags); virtual ElementaryStreamQueue* createESQueue( ElementaryStreamQueue::Mode mode, uint32_t flags = 0); virtual CameraSource *CreateCameraSourceFromCamera( @@ -152,6 +154,8 @@ struct AVUtils { virtual bool isAudioMuxFormatSupported(const char *mime); virtual void cacheCaptureBuffers(sp camera, video_encoder encoder); + virtual void getHFRParams(bool*, int32_t*, sp); + virtual int64_t overwriteTimeOffset(bool, int64_t, int64_t *, int64_t, int32_t); virtual const char *getCustomCodecsLocation(); virtual const char *getCustomCodecsPerformanceLocation(); diff --git a/media/libavextensions/stagefright/AVFactory.cpp b/media/libavextensions/stagefright/AVFactory.cpp index fe8c614ad..65e661f9e 100644 --- a/media/libavextensions/stagefright/AVFactory.cpp +++ b/media/libavextensions/stagefright/AVFactory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -54,7 +54,8 @@ sp AVFactory::createACodec() { } MediaExtractor* AVFactory::createExtendedExtractor( - const sp &, const char *, const sp &) { + const sp &, const char *, const sp &, + const uint32_t) { return NULL; } diff --git a/media/libavextensions/stagefright/AVUtils.cpp b/media/libavextensions/stagefright/AVUtils.cpp index e02657869..b936e0435 100644 --- a/media/libavextensions/stagefright/AVUtils.cpp +++ b/media/libavextensions/stagefright/AVUtils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 - 2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2013 - 2017, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -135,6 +135,15 @@ void AVUtils::cacheCaptureBuffers(sp, video_encoder) { return; } +void AVUtils::getHFRParams(bool*, int32_t*, sp) { + return; +} + +int64_t AVUtils::overwriteTimeOffset(bool, int64_t inputBufferTimeOffsetUs, int64_t*, + int64_t, int32_t) { + return inputBufferTimeOffsetUs; +} + const char *AVUtils::getCustomCodecsLocation() { return "/etc/media_codecs.xml"; } diff --git a/media/libavextensions/stagefright/ExtendedMediaDefs.cpp b/media/libavextensions/stagefright/ExtendedMediaDefs.cpp index 20437ebdf..c02867ed1 100644 --- a/media/libavextensions/stagefright/ExtendedMediaDefs.cpp +++ b/media/libavextensions/stagefright/ExtendedMediaDefs.cpp @@ -67,6 +67,6 @@ const char *MEDIA_MIMETYPE_VIDEO_MPEG4_DP = "video/mp4v-esdp"; const char *MEDIA_MIMETYPE_CONTAINER_DSF = "audio/x-dsf"; // For DSF clip const char *MEDIA_MIMETYPE_CONTAINER_DFF = "audio/x-dff"; // For DFF or DIF clip const char *MEDIA_MIMETYPE_AUDIO_DSD = "audio/dsd"; - +const char *MEDIA_MIMETYPE_CONTAINER_MOV = "video/quicktime"; //mov clip } // namespace android diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 149449570..93700ed70 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -274,9 +274,9 @@ status_t AudioRecord::set( // TODO: add audio hardware input latency here if (mTransfer == TRANSFER_CALLBACK || mTransfer == TRANSFER_SYNC) { - mLatency = (1000 * mNotificationFramesAct) / sampleRate; + mLatency = (1000 * mNotificationFramesAct) / mSampleRate; } else { - mLatency = (1000 * mFrameCount) / sampleRate; + mLatency = (1000 * mFrameCount) / mSampleRate; } mMarkerPosition = 0; mMarkerReached = false; @@ -875,7 +875,7 @@ audio_io_handle_t AudioRecord::getInputPrivate() const ssize_t AudioRecord::read(void* buffer, size_t userSize, bool blocking) { - if (mTransfer != TRANSFER_SYNC) { + if ((mTransfer != TRANSFER_SYNC) || !mActive) { return INVALID_OPERATION; } diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp index d170c222d..0fb95806f 100644 --- a/media/libmedia/IMediaExtractorService.cpp +++ b/media/libmedia/IMediaExtractorService.cpp @@ -38,10 +38,12 @@ class BpMediaExtractorService : public BpInterface { } - virtual sp makeExtractor(const sp &source, const char *mime) { + virtual sp makeExtractor(const sp &source, const char *mime, + const uint32_t extFlags) { Parcel data, reply; data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor()); data.writeStrongBinder(IInterface::asBinder(source)); + data.writeUint32(extFlags); if (mime != NULL) { data.writeCString(mime); } @@ -75,8 +77,10 @@ status_t BnMediaExtractorService::onTransact( // for MediaBuffers for this process. MediaBuffer::useSharedMemory(); sp source = interface_cast(b); + uint32_t extFlags; + data.readUint32(&extFlags); const char *mime = data.readCString(); - sp ex = makeExtractor(source, mime); + sp ex = makeExtractor(source, mime, extFlags); reply->writeStrongBinder(IInterface::asBinder(ex)); return NO_ERROR; } diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index bb9a26fe1..5936a36b5 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include "WebmWriter.h" #include "StagefrightRecorder.h" @@ -1464,7 +1465,7 @@ status_t StagefrightRecorder::setupCameraSource( Size videoSize; videoSize.width = mVideoWidth; videoSize.height = mVideoHeight; - if (mCaptureFpsEnable) { + if (mCaptureFpsEnable && mCaptureFps != mFrameRate ) { if (mTimeBetweenCaptureUs < 0) { ALOGE("Invalid mTimeBetweenTimeLapseFrameCaptureUs value: %" PRId64 "", mTimeBetweenCaptureUs); @@ -1477,10 +1478,11 @@ status_t StagefrightRecorder::setupCameraSource( mTimeBetweenCaptureUs); *cameraSource = mCameraSourceTimeLapse; } else { - *cameraSource = AVFactory::get()->CreateCameraSourceFromCamera( + mCameraSource = AVFactory::get()->CreateCameraSourceFromCamera( mCamera, mCameraProxy, mCameraId, mClientName, mClientUid, mClientPid, videoSize, mFrameRate, mPreviewSurface); + *cameraSource = mCameraSource; } AVUtils::get()->cacheCaptureBuffers(mCamera, mVideoEncoder); mCamera.clear(); @@ -1609,6 +1611,7 @@ status_t StagefrightRecorder::setupVideoEncoder( preferBFrames = false; tsLayers = 2; // use at least two layers as resulting video will likely be sped up } else if (mCaptureFps > maxPlaybackFps) { // slow-mo + format->setInt32("high-frame-rate", 1); maxPlaybackFps = mCaptureFps; // assume video will be played back at full capture speed preferBFrames = false; } @@ -1882,6 +1885,13 @@ status_t StagefrightRecorder::stop() { mCameraSourceTimeLapse = NULL; } + if (mVideoEncoderSource != NULL) { + mVideoEncoderSource->notifyPerformanceMode(); + } + if (mCameraSource != NULL) { + mCameraSource->notifyPerformanceMode(); + } + if (mWriter != NULL) { err = mWriter->stop(); mWriter.clear(); @@ -1960,6 +1970,7 @@ status_t StagefrightRecorder::reset() { mCaptureFps = 0.0f; mTimeBetweenCaptureUs = -1; mCameraSourceTimeLapse = NULL; + mCameraSource = NULL; mMetaDataStoredInVideoBuffers = kMetadataBufferTypeInvalid; mEncoderProfiles = MediaProfiles::getInstance(); mRotationDegrees = 0; diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 01ce38001..7caa24993 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -121,6 +121,7 @@ struct StagefrightRecorder : public MediaRecorderBase { float mCaptureFps; int64_t mTimeBetweenCaptureUs; sp mCameraSourceTimeLapse; + sp mCameraSource; String8 mParams; diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index e20b26e16..9f6a737b1 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -180,7 +180,8 @@ status_t NuPlayer::GenericSource::initFromDataSource() { extractor = mWVMExtractor; } else { extractor = MediaExtractor::Create(mDataSource, - mimeType.isEmpty() ? NULL : mimeType.string()); + mimeType.isEmpty() ? NULL : mimeType.string(), + mIsStreaming ? 0 : AVNuUtils::get()->getFlags()); } if (extractor == NULL) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index effabe155..71ceff39a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -1132,10 +1132,10 @@ void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) { if (nowUs >= mNextAudioClockUpdateTimeUs) { int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs); mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs); - mAnchorTimeMediaUs = mediaTimeUs; mUseVirtualAudioSink = false; mNextAudioClockUpdateTimeUs = nowUs + kMinimumAudioClockUpdatePeriodUs; } + mAnchorTimeMediaUs = mediaTimeUs; } else { int64_t unused; if ((mMediaClock->getMediaTime(nowUs, &unused) != OK) @@ -1792,10 +1792,12 @@ void NuPlayer::Renderer::onAudioTearDown(AudioTearDownReason reason) { void NuPlayer::Renderer::startAudioOffloadPauseTimeout() { if (offloadingAudio()) { + int64_t pauseTimeOutDuration = property_get_int64( + "audio.offload.pstimeout.secs",(kOffloadPauseMaxUs/1000000)/*default*/); mWakeLock->acquire(); sp msg = new AMessage(kWhatAudioOffloadPauseTimeout, this); msg->setInt32("drainGeneration", mAudioOffloadPauseTimeoutGeneration); - msg->post(kOffloadPauseMaxUs); + msg->post(pauseTimeOutDuration*1000000); } } diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index bad08aa6e..f98837619 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -506,6 +506,22 @@ sp MPEG4Extractor::getTrackMetaData( const char *mime; CHECK(track->meta->findCString(kKeyMIMEType, &mime)); if (!strncasecmp("video/", mime, 6)) { + // MPEG2 tracks do not provide CSD, so read the stream header + if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)) { + off64_t offset; + size_t size; + if (track->sampleTable->getMetaDataForSample( + 0 /* sampleIndex */, &offset, &size, NULL /* sampleTime */) == OK) { + if (size > kMaxTrackHeaderSize) { + size = kMaxTrackHeaderSize; + } + uint8_t header[kMaxTrackHeaderSize]; + if (mDataSource->readAt(offset, &header, size) == (ssize_t)size) { + track->meta->setData(kKeyStreamHeader, 'mdat', header, size); + } + } + } + if (mMoofOffset > 0) { int64_t duration; if (track->meta->findInt64(kKeyDuration, &duration)) { @@ -526,22 +542,6 @@ sp MPEG4Extractor::getTrackMetaData( ((int64_t)sampleTime * 1000000) / track->timescale); } } - - // MPEG2 tracks do not provide CSD, so read the stream header - if (!strcmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)) { - off64_t offset; - size_t size; - if (track->sampleTable->getMetaDataForSample( - 0 /* sampleIndex */, &offset, &size, NULL /* sampleTime */) == OK) { - if (size > kMaxTrackHeaderSize) { - size = kMaxTrackHeaderSize; - } - uint8_t header[kMaxTrackHeaderSize]; - if (mDataSource->readAt(offset, &header, size) == (ssize_t)size) { - track->meta->setData(kKeyStreamHeader, 'mdat', header, size); - } - } - } } } @@ -1271,6 +1271,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { ALOGV("allocated pssh @ %p", pssh.data); ssize_t requested = (ssize_t) pssh.datalen; if (mDataSource->readAt(data_offset + 24, pssh.data, requested) < requested) { + delete[] pssh.data; return ERROR_IO; } mPssh.push_back(pssh); diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp index 796a74fa3..9e9113bf8 100644 --- a/media/libstagefright/MPEG4Writer.cpp +++ b/media/libstagefright/MPEG4Writer.cpp @@ -70,6 +70,7 @@ static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32 static const uint8_t kNalUnitTypeSeqParamSet = 0x07; static const uint8_t kNalUnitTypePicParamSet = 0x08; static const int64_t kInitialDelayTimeUs = 700000LL; +static const nsecs_t kWaitDuration = 500000000LL; //500msec ~15frames delay static const char kMetaKey_Version[] = "com.android.version"; #ifdef SHOW_MODEL_BUILD @@ -407,6 +408,10 @@ class MPEG4Writer::Track { Track(const Track &); Track &operator=(const Track &); + + bool mIsStopping; + Mutex mTrackCompletionLock; + Condition mTrackCompletionSignal; }; MPEG4Writer::MPEG4Writer(int fd) @@ -436,7 +441,8 @@ MPEG4Writer::MPEG4Writer(int fd) mAreGeoTagsAvailable(false), mStartTimeOffsetMs(-1), mMetaKeys(new AMessage()), - mIsAudioAMR(false) { + mIsAudioAMR(false), + mLastAudioTimeStampUs(0) { addDeviceMeta(); // Verify mFd is seekable @@ -966,8 +972,9 @@ status_t MPEG4Writer::reset() { status_t err = OK; int64_t maxDurationUs = 0; int64_t minDurationUs = 0x7fffffffffffffffLL; - for (List::iterator it = mTracks.begin(); - it != mTracks.end(); ++it) { + List::iterator it = mTracks.end(); + do { + --it; status_t status = (*it)->stop(); if (err == OK && status != OK) { err = status; @@ -980,7 +987,7 @@ status_t MPEG4Writer::reset() { if (durationUs < minDurationUs) { minDurationUs = durationUs; } - } + } while (it != mTracks.begin()); if (mTracks.size() > 1) { ALOGD("Duration from tracks range is [%" PRId64 ", %" PRId64 "] us", @@ -1586,6 +1593,7 @@ MPEG4Writer::Track::Track( } setTimeScale(); + mIsStopping = false; } void MPEG4Writer::Track::updateTrackSizeEstimate() { @@ -1996,6 +2004,17 @@ status_t MPEG4Writer::Track::stop() { if (mDone) { return OK; } + + if (!mIsAudio && mOwner->getLastAudioTimeStamp() && + !mOwner->exceedsFileDurationLimit() && + !mOwner->exceedsFileSizeLimit() && + !mIsMalformed) { + Mutex::Autolock lock(mTrackCompletionLock); + mIsStopping = true; + if (mTrackCompletionSignal.waitRelative(mTrackCompletionLock, kWaitDuration)) { + ALOGW("Timed-out waiting for video track to reach final audio timestamp !"); + } + } mDone = true; ALOGD("%s track source stopping", mIsAudio? "Audio": "Video"); @@ -2776,6 +2795,15 @@ status_t MPEG4Writer::Track::threadEntry() { } } + if (mIsAudio) { + mOwner->setLastAudioTimeStamp(lastTimestampUs); + } else if (mIsStopping && timestampUs >= mOwner->getLastAudioTimeStamp()) { + ALOGI("Video time (%lld) reached last audio time (%lld)", (long long)timestampUs, (long long)mOwner->getLastAudioTimeStamp()); + Mutex::Autolock lock(mTrackCompletionLock); + mTrackCompletionSignal.signal(); + break; + } + } if (isTrackMalFormed()) { @@ -3466,7 +3494,7 @@ void MPEG4Writer::Track::writeCttsBox() { mOwner->beginBox("ctts"); mOwner->writeInt32(0); // version=0, flags=0 - uint32_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime(); + int64_t delta = mMinCttsOffsetTimeUs - getStartTimeOffsetScaledTime(); mCttsTableEntries->adjustEntries([delta](size_t /* ix */, uint32_t (&value)[2]) { // entries are pairs; adjust only ctts uint32_t duration = htonl(value[1]); // back to host byte order diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp old mode 100755 new mode 100644 index fda48014f..bcd2a051d --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -189,7 +189,6 @@ void MediaCodecSource::Puller::stop() { interrupt = queue->mReadPendingSince && (queue->mReadPendingSince < ALooper::GetNowUs() - 1000000); queue->flush(); // flush any unprocessed pulled buffers } - } void MediaCodecSource::Puller::interruptSource() { @@ -329,7 +328,7 @@ sp MediaCodecSource::Create( uint32_t flags) { sp mediaSource = new MediaCodecSource(looper, format, source, consumer, flags); - + AVUtils::get()->getHFRParams(&mediaSource->mIsHFR, &mediaSource->mBatchSize, format); if (mediaSource->init() == OK) { return mediaSource; } @@ -422,7 +421,10 @@ MediaCodecSource::MediaCodecSource( mFirstSampleSystemTimeUs(-1ll), mPausePending(false), mFirstSampleTimeUs(-1ll), - mGeneration(0) { + mGeneration(0), + mPrevBufferTimestampUs(0), + mIsHFR(false), + mBatchSize(0) { CHECK(mLooper != NULL); AString mime; @@ -685,13 +687,15 @@ status_t MediaCodecSource::feedEncoderInputBuffers() { return OK; } } - + mInputBufferTimeOffsetUs = AVUtils::get()->overwriteTimeOffset(mIsHFR, + mInputBufferTimeOffsetUs, &mPrevBufferTimestampUs, timeUs, mBatchSize); timeUs += mInputBufferTimeOffsetUs; // push decoding time for video, or drift time for audio if (mIsVideo) { mDecodingTimeQueue.push_back(timeUs); if (mFlags & FLAG_USE_METADATA_INPUT) { + mbuf->meta_data()->setInt64(kKeyTime, timeUs); AVUtils::get()->addDecodingTimesFromBatch(mbuf, mDecodingTimeQueue); } } else { @@ -710,7 +714,9 @@ status_t MediaCodecSource::feedEncoderInputBuffers() { sp inbuf; status_t err = mEncoder->getInputBuffer(bufferIndex, &inbuf); - if (err != OK || inbuf == NULL) { + + if (err != OK || inbuf == NULL || inbuf->data() == NULL + || mbuf->data() == NULL || mbuf->size() == 0) { mbuf->release(); signalEOS(err); break; @@ -877,12 +883,20 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { sp outbuf; status_t err = mEncoder->getOutputBuffer(index, &outbuf); - if (err != OK || outbuf == NULL) { + if (err != OK || outbuf == NULL || outbuf->data() == NULL + || outbuf->size() == 0) { signalEOS(err); break; } MediaBuffer *mbuf = new MediaBuffer(outbuf->size()); + if (mbuf == NULL || mbuf->data() == NULL || mbuf->size() == 0) { + if ( mbuf ) + mbuf->release(); + signalEOS(err); + break; + } + sp meta = mbuf->meta_data(); AVUtils::get()->setDeferRelease(meta); mbuf->setObserver(this); @@ -1071,4 +1085,12 @@ void MediaCodecSource::onMessageReceived(const sp &msg) { } } +void MediaCodecSource::notifyPerformanceMode() { + if (mIsVideo && mEncoder != NULL) { + sp params = new AMessage; + params->setInt32("qti.request.perf", true); + mEncoder->setParameters(params); + } +} + } // namespace android diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 92f8b291f..5aaa3cbd6 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -143,15 +143,16 @@ sp RemoteDataSource::DrmInitialization(const char *mime) { // static sp MediaExtractor::Create( - const sp &source, const char *mime) { - ALOGV("MediaExtractor::Create %s", mime); + const sp &source, const char *mime, + const uint32_t flags) { + ALOGV("MediaExtractor::Create %s flags %d", mime, flags); char value[PROPERTY_VALUE_MAX]; if (property_get("media.stagefright.extractremote", value, NULL) && (!strcmp("0", value) || !strcasecmp("false", value))) { // local extractor ALOGW("creating media extractor in calling process"); - return CreateFromService(source, mime); + return CreateFromService(source, mime, flags); } else { // Check if it's WVM, since WVMExtractor needs to be created in the media server process, // not the extractor process. @@ -180,7 +181,7 @@ sp MediaExtractor::Create( if (binder != 0) { sp mediaExService(interface_cast(binder)); - sp ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime); + sp ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime, flags); return ex; } else { ALOGE("extractor service not running"); @@ -191,9 +192,10 @@ sp MediaExtractor::Create( } sp MediaExtractor::CreateFromService( - const sp &source, const char *mime) { + const sp &source, const char *mime, + const uint32_t flags) { - ALOGV("MediaExtractor::CreateFromService %s", mime); + ALOGV("MediaExtractor::CreateFromService %s flags %d", mime, flags); DataSource::RegisterDefaultSniffers(); sp meta; @@ -235,7 +237,7 @@ sp MediaExtractor::CreateFromService( } MediaExtractor *ret = NULL; - if ((ret = AVFactory::get()->createExtendedExtractor(source, mime, meta)) != NULL) { + if ((ret = AVFactory::get()->createExtendedExtractor(source, mime, meta, flags)) != NULL) { } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4) || !strcasecmp(mime, "audio/mp4")) { ret = new MPEG4Extractor(source); diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp index 37e8e9c82..ebbe5102e 100644 --- a/media/libstagefright/OggExtractor.cpp +++ b/media/libstagefright/OggExtractor.cpp @@ -697,7 +697,21 @@ status_t MyOggExtractor::_readNextPacket(MediaBuffer **out, bool calcVorbisTimes if (buffer != NULL) { fullSize += buffer->range_length(); } - MediaBuffer *tmp = new MediaBuffer(fullSize); + if (fullSize > 16 * 1024 * 1024) { // arbitrary limit of 16 MB packet size + if (buffer != NULL) { + buffer->release(); + } + ALOGE("b/36592202"); + return ERROR_MALFORMED; + } + MediaBuffer *tmp = new (std::nothrow) MediaBuffer(fullSize); + if (tmp == NULL) { + if (buffer != NULL) { + buffer->release(); + } + ALOGE("b/36592202"); + return ERROR_MALFORMED; + } if (buffer != NULL) { memcpy(tmp->data(), buffer->data(), buffer->range_length()); tmp->set_range(0, buffer->range_length()); diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp index aa508065a..cd3a54ede 100644 --- a/media/libstagefright/StagefrightMetadataRetriever.cpp +++ b/media/libstagefright/StagefrightMetadataRetriever.cpp @@ -694,6 +694,10 @@ void StagefrightMetadataRetriever::parseMetaData() { continue; } + if (trackMeta == NULL) { + continue; + } + int64_t durationUs; if (trackMeta->findInt64(kKeyDuration, &durationUs)) { if (durationUs > maxDurationUs) { @@ -777,7 +781,8 @@ void StagefrightMetadataRetriever::parseMetaData() { if (!strcasecmp(fileMIME, "video/x-matroska")) { sp trackMeta = mExtractor->getTrackMetaData(0); const char *trackMIME; - CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME)); + CHECK(trackMeta != NULL + && trackMeta->findCString(kKeyMIMEType, &trackMIME)); if (!strncasecmp("audio/", trackMIME, 6)) { // The matroska file only contains a single audio track, diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp index 9e7a3be15..5b06722fb 100644 --- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp +++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp @@ -614,6 +614,7 @@ OMX_ERRORTYPE SoftAVC::initEncoder() { IV_STATUS_T status; WORD32 level; uint32_t displaySizeY; + CHECK(!mStarted); OMX_ERRORTYPE errType = OMX_ErrorNone; @@ -917,6 +918,9 @@ OMX_ERRORTYPE SoftAVC::releaseEncoder() { } } + // clear other pointers into the space being free()d + mCodecCtx = NULL; + mStarted = false; return OMX_ErrorNone; @@ -1509,6 +1513,14 @@ void SoftAVC::onQueueFilled(OMX_U32 portIndex) { return; } +void SoftAVC::onReset() { + SoftVideoEncoderOMXComponent::onReset(); + + if (releaseEncoder() != OMX_ErrorNone) { + ALOGW("releaseEncoder failed"); + } +} + } // namespace android android::SoftOMXComponent *createSoftOMXComponent( diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h index cf6f899af..8b24b629e 100644 --- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.h +++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.h @@ -136,6 +136,8 @@ struct SoftAVC : public SoftVideoEncoderOMXComponent { protected: virtual ~SoftAVC(); + virtual void onReset(); + private: enum { kNumBuffers = 2, diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp old mode 100644 new mode 100755 index a60296c74..c66dc3562 --- a/media/libstagefright/httplive/LiveSession.cpp +++ b/media/libstagefright/httplive/LiveSession.cpp @@ -434,6 +434,14 @@ status_t LiveSession::dequeueAccessUnit( } else { mDiscontinuityAbsStartTimesUs.add(strm.mCurDiscontinuitySeq, timeUs); firstTimeUs = timeUs; + // we have adjusted a/v both start from last preceding IDR position, it's always + // before original seek position, so we need to adjust mLastSeekTimeUs to the + // actual start position + int64_t newSeekTimeUs = -1; + if ((*accessUnit)->meta()->findInt64("newSeekTimeUs", &newSeekTimeUs) + && newSeekTimeUs != -1) { + mLastSeekTimeUs = newSeekTimeUs; + } } strm.mLastDequeuedTimeUs = timeUs; diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp old mode 100644 new mode 100755 index f569e0114..c3d465084 --- a/media/libstagefright/httplive/PlaylistFetcher.cpp +++ b/media/libstagefright/httplive/PlaylistFetcher.cpp @@ -1586,6 +1586,8 @@ const sp &PlaylistFetcher::setAccessUnitProperties( if (discard) { accessUnit->meta()->setInt32("discard", discard); + } else { + accessUnit->meta()->setInt64("newSeekTimeUs", mLastIDRTimeUs); } accessUnit->meta()->setInt32("discontinuitySeq", mDiscontinuitySeq); diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp index 00e3a772d..7143d5431 100644 --- a/media/libstagefright/omx/OMXNodeInstance.cpp +++ b/media/libstagefright/omx/OMXNodeInstance.cpp @@ -796,6 +796,12 @@ status_t OMXNodeInstance::useBuffer( return BAD_VALUE; } + if (!mSailed) { + ALOGE("b/35467458"); + android_errorWriteLog(0x534e4554, "35467458"); + return BAD_VALUE; + } + // metadata buffers are not connected cross process // use a backup buffer instead of the actual buffer BufferMeta *buffer_meta; @@ -1231,6 +1237,12 @@ status_t OMXNodeInstance::allocateSecureBuffer( Mutex::Autolock autoLock(mLock); + if (!mSailed) { + ALOGE("b/35467458"); + android_errorWriteLog(0x534e4554, "35467458"); + return BAD_VALUE; + } + BufferMeta *buffer_meta = new BufferMeta(size, portIndex); OMX_BUFFERHEADERTYPE *header; @@ -1286,6 +1298,12 @@ status_t OMXNodeInstance::allocateBufferWithBackup( return BAD_VALUE; } + if (!mSailed) { + ALOGE("b/35467458"); + android_errorWriteLog(0x534e4554, "35467458"); + return BAD_VALUE; + } + // metadata buffers are not connected cross process; only copy if not meta #ifdef CAMCORDER_GRALLOC_SOURCE bool copy = true; diff --git a/services/audioflinger/AudioResamplerQTI.cpp b/services/audioflinger/AudioResamplerQTI.cpp index 0f1d26fa1..ccd9cc7a0 100644 --- a/services/audioflinger/AudioResamplerQTI.cpp +++ b/services/audioflinger/AudioResamplerQTI.cpp @@ -25,7 +25,7 @@ namespace android { AudioResamplerQTI::AudioResamplerQTI(int format, int inChannelCount, int32_t sampleRate) :AudioResampler(inChannelCount, sampleRate, QTI_QUALITY), - mTmpBuf(0), mResamplerOutBuf(0), mFrameIndex(0),mOutFrameCount(0) + mTmpBuf(0), mResamplerOutBuf(0), mFrameIndex(0),mOutFrameCount(0), mInFrameRequest(0) { stateSize = QCT_Resampler::MemAlloc(format, inChannelCount, sampleRate, sampleRate); mState = new int16_t[stateSize]; @@ -67,15 +67,18 @@ size_t AudioResamplerQTI::resample(int32_t* out, size_t outFrameCount, inFrameRequest = inFrameCount * 2; } - if (mOutFrameCount < outFrameCount) { - mOutFrameCount = outFrameCount; + if (mInFrameRequest < inFrameRequest) { + mInFrameRequest = inFrameRequest; if (mTmpBuf) { delete [] mTmpBuf; } + mTmpBuf = new int32_t[inFrameRequest + 16]; + } + if (mOutFrameCount < outFrameCount) { + mOutFrameCount = outFrameCount; if(mResamplerOutBuf) { delete [] mResamplerOutBuf; } - mTmpBuf = new int32_t[inFrameRequest + 16]; mResamplerOutBuf = new int32_t[out_count]; } diff --git a/services/audioflinger/AudioResamplerQTI.h b/services/audioflinger/AudioResamplerQTI.h index 1cf93fc56..3cf46eca2 100644 --- a/services/audioflinger/AudioResamplerQTI.h +++ b/services/audioflinger/AudioResamplerQTI.h @@ -40,6 +40,7 @@ class AudioResamplerQTI : public AudioResampler { size_t mFrameIndex; size_t stateSize; size_t mOutFrameCount; + size_t mInFrameRequest; static const int kNumTmpBufSize = 1024; diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 0cd43b1e4..ec677ae5f 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -5270,7 +5270,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep } } if ((track->sharedBuffer() != 0) || track->isStopped() || - track->isStopping_2() || track->isPaused()) { + track->isStopping_2()) { // We have consumed all the buffers of this track. // Remove it from the list of active tracks. size_t audioHALFrames; diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 0683f4f8d..da15556b3 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -1477,9 +1477,11 @@ status_t AudioFlinger::PlaybackThread::PatchTrack::obtainBuffer(Proxy::Buffer* b status_t status = NO_ERROR; static const int32_t kMaxTries = 5; int32_t tryCounter = kMaxTries; + size_t frameCount = buffer->mFrameCount; do { if (status == NOT_ENOUGH_DATA) { restartIfDisabled(); + buffer->mFrameCount = frameCount; } status = mProxy->obtainBuffer(buffer, timeOut); } while ((status == NOT_ENOUGH_DATA) && (tryCounter-- > 0)); diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 1346870b1..69d1f8288 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -4431,36 +4431,6 @@ void AudioPolicyManager::checkA2dpSuspend() if ((a2dpOutput != 0) && !a2dpOnPrimary) { mpClientInterface->suspendOutput(a2dpOutput); } - // if a2dp on primay, need to mute the strategies which device is a2dp when suspended - if (a2dpOnPrimary) { - uint32_t muteWaitMs = 0; - for (int i = 0; i < NUM_STRATEGIES; i++) { - audio_devices_t curDevice = getDeviceForStrategy((routing_strategy)i, false /*fromCache*/); - bool mute = (popcount(curDevice) == 1) && (curDevice & AUDIO_DEVICE_OUT_ALL_A2DP); - for (size_t j = 0; j < mOutputs.size(); j++) { - sp desc = mOutputs.valueAt(j); - // skip output if it does not share any device with a2dp devices - if ((desc->supportedDevices() & AUDIO_DEVICE_OUT_ALL_A2DP) - == AUDIO_DEVICE_NONE) { - continue; - } - if (mute) { - desc->mStrategyMutedByA2dpSuspended[i] = true; - setStrategyMute((routing_strategy)i, mute, desc); - if (isStrategyActive(desc, (routing_strategy)i)) { - // as explained in checkDeviceMuteStrategy(), the mute time should - // be set to account for the delay between now and the next time the - // audioflinger thread for this output will process a buffer, and - // long enough to wait for PCM with previous volume applied empty. - if (muteWaitMs < desc->latency()) { - muteWaitMs = desc->latency(); - } - } - } - } - } - usleep(muteWaitMs * 1000); - } mA2dpSuspended = true; } } diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp index 08a06effe..86887bd9d 100644 --- a/services/camera/libcameraservice/api1/Camera2Client.cpp +++ b/services/camera/libcameraservice/api1/Camera2Client.cpp @@ -430,9 +430,10 @@ binder::Status Camera2Client::disconnect() { ALOGV("Camera %d: Disconnecting device", mCameraId); - mDevice->disconnect(); - - mDevice.clear(); + if (mDevice != nullptr) { + mDevice->disconnect(); + mDevice.clear(); + } CameraService::Client::disconnect(); @@ -878,6 +879,7 @@ void Camera2Client::stopPreview() { Mutex::Autolock icl(mBinderSerializationLock); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return; + if (mDevice == 0) return; stopPreviewL(); } @@ -1336,7 +1338,7 @@ status_t Camera2Client::cancelAutoFocus() { ALOGV("%s: Camera %d", __FUNCTION__, mCameraId); status_t res; if ( (res = checkPid(__FUNCTION__) ) != OK) return res; - + if (mDevice == 0) return NO_INIT; int triggerId; { SharedParameters::Lock l(mParameters); diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp index a7fe5e732..9ed2ca50c 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp @@ -76,7 +76,15 @@ CameraDeviceClient::CameraDeviceClient(const sp& cameraService, cameraId, cameraFacing, clientPid, clientUid, servicePid), mInputStream(), mStreamingRequestId(REQUEST_ID_NONE), - mRequestIdCounter(0) { + mRequestIdCounter(0), + mPrivilegedClient(false) { + + char value[PROPERTY_VALUE_MAX]; + property_get("persist.camera.cfa.packagelist", value, ""); + String16 packagelist(value); + if (packagelist.contains(clientPackageName.string())) { + mPrivilegedClient = true; + } ATRACE_CALL(); ALOGI("CameraDeviceClient %d: Opened", cameraId); @@ -487,7 +495,7 @@ binder::Status CameraDeviceClient::createStream( int32_t allowedFlags = GraphicBuffer::USAGE_SW_READ_MASK | GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_HW_COMPOSER; - bool flexibleConsumer = (consumerUsage & disallowedFlags) == 0 && + bool flexibleConsumer = !mPrivilegedClient && (consumerUsage & disallowedFlags) == 0 && (consumerUsage & allowedFlags) != 0; sp binder = IInterface::asBinder(bufferProducer); diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h index dde23fb9d..764938ed8 100644 --- a/services/camera/libcameraservice/api2/CameraDeviceClient.h +++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h @@ -225,6 +225,7 @@ class CameraDeviceClient : static const int32_t REQUEST_ID_NONE = -1; int32_t mRequestIdCounter; + bool mPrivilegedClient; // The list of output streams whose surfaces are deferred. We have to track them separately // as there are no surfaces available and can not be put into mStreamMap. Once the deferred diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp index eece01b46..c324ac6f5 100644 --- a/services/camera/libcameraservice/device3/Camera3Device.cpp +++ b/services/camera/libcameraservice/device3/Camera3Device.cpp @@ -471,9 +471,6 @@ ssize_t Camera3Device::getJpegBufferSize(uint32_t width, uint32_t height) const (maxJpegResolution.width * maxJpegResolution.height); ssize_t jpegBufferSize = scaleFactor * (maxJpegBufferSize - kMinJpegBufferSize) + kMinJpegBufferSize; - if (jpegBufferSize > maxJpegBufferSize) { - jpegBufferSize = maxJpegBufferSize; - } return jpegBufferSize; } diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp index 4a8016651..022dad82b 100644 --- a/services/mediaextractor/MediaExtractorService.cpp +++ b/services/mediaextractor/MediaExtractorService.cpp @@ -27,12 +27,13 @@ namespace android { sp MediaExtractorService::makeExtractor( - const sp &remoteSource, const char *mime) { - ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime); + const sp &remoteSource, const char *mime, + const uint32_t extFlags) { + ALOGV("@@@ MediaExtractorService::makeExtractor for %s extFlags %d", mime, extFlags); sp localSource = DataSource::CreateFromIDataSource(remoteSource); - sp ret = MediaExtractor::CreateFromService(localSource, mime); + sp ret = MediaExtractor::CreateFromService(localSource, mime, extFlags); ALOGV("extractor service created %p (%s)", ret.get(), diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h index 078af0c22..7e315e6a6 100644 --- a/services/mediaextractor/MediaExtractorService.h +++ b/services/mediaextractor/MediaExtractorService.h @@ -33,7 +33,8 @@ class MediaExtractorService : public BinderService, publi static const char* getServiceName() { return "media.extractor"; } - virtual sp makeExtractor(const sp &source, const char *mime); + virtual sp makeExtractor(const sp &source, const char *mime, + const uint32_t extFlags); virtual status_t dump(int fd, const Vector& args); virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp index 74d0c7010..f1f2eaadc 100644 --- a/services/soundtrigger/SoundTriggerHwService.cpp +++ b/services/soundtrigger/SoundTriggerHwService.cpp @@ -87,8 +87,7 @@ void SoundTriggerHwService::onFirstRef() ALOGI("loaded default module %s, handle %d", descriptor.properties.description, descriptor.handle); - sp client; - sp module = new Module(this, dev, descriptor, client); + sp module = new Module(this, dev, descriptor); mModules.add(descriptor.handle, module); mCallbackThread = new CallbackThread(this); } @@ -143,11 +142,13 @@ status_t SoundTriggerHwService::attach(const sound_trigger_module_handle_t handl } sp module = mModules.valueAt(index); - module->setClient(client); - IInterface::asBinder(client)->linkToDeath(module); - moduleInterface = module; + sp moduleClient = module->addClient(client); + if (moduleClient == 0) { + return NO_INIT; + } - module->setCaptureState_l(mCaptureState); + moduleClient->setCaptureState_l(mCaptureState); + moduleInterface = moduleClient; return NO_ERROR; } @@ -164,14 +165,6 @@ status_t SoundTriggerHwService::setCaptureState(bool active) } -void SoundTriggerHwService::detachModule(sp module) -{ - ALOGV("detachModule"); - AutoMutex lock(mServiceLock); - module->clearClient(); -} - - static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 60000; @@ -324,8 +317,10 @@ void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognitio return; } - sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, - eventMemory, strongModule)); + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, + eventMemory); + callbackEvent->setModule(strongModule); + sendCallbackEvent_l(callbackEvent); } // static @@ -336,6 +331,7 @@ void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event if (module == NULL) { return; } + sp service = module->service().promote(); if (service == 0) { return; @@ -377,8 +373,10 @@ void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event if (strongModule == 0) { return; } - sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL, - eventMemory, strongModule)); + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL, + eventMemory); + callbackEvent->setModule(strongModule); + sendCallbackEvent_l(callbackEvent); } @@ -414,8 +412,24 @@ void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_ if (strongModule == 0) { return; } - sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE, - eventMemory, strongModule)); + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE, + eventMemory); + callbackEvent->setModule(strongModule); + sendCallbackEvent_l(callbackEvent); +} + +void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state, + ModuleClient *moduleClient) +{ + sp eventMemory = prepareServiceStateEvent_l(state); + if (eventMemory == 0) { + return; + } + + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE, + eventMemory); + callbackEvent->setModuleClient(moduleClient); + sendCallbackEvent_l(callbackEvent); } // call with mServiceLock held @@ -428,14 +442,25 @@ void SoundTriggerHwService::onCallbackEvent(const sp& event) { ALOGV("onCallbackEvent"); sp module; + sp moduleClient; { AutoMutex lock(mServiceLock); + //CallbackEvent is either for Module or ModuleClient module = event->mModule.promote(); if (module == 0) { - return; + moduleClient = event->mModuleClient.promote(); + if (moduleClient == 0) { + return; + } } } - module->onCallbackEvent(event); + if (module != 0) { + ALOGV("onCallbackEvent for module"); + module->onCallbackEvent(event); + } else if (moduleClient != 0) { + ALOGV("onCallbackEvent for moduleClient"); + moduleClient->onCallbackEvent(event); + } { AutoMutex lock(mServiceLock); // clear now to execute with mServiceLock locked @@ -505,9 +530,8 @@ void SoundTriggerHwService::CallbackThread::sendCallbackEvent( mCallbackCond.signal(); } -SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp memory, - wp module) - : mType(type), mMemory(memory), mModule(module) +SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp memory) + : mType(type), mMemory(memory) { } @@ -521,51 +545,75 @@ SoundTriggerHwService::CallbackEvent::~CallbackEvent() SoundTriggerHwService::Module::Module(const sp& service, sound_trigger_hw_device* hwDevice, - sound_trigger_module_descriptor descriptor, - const sp& client) + sound_trigger_module_descriptor descriptor) : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor), - mClient(client), mServiceState(SOUND_TRIGGER_STATE_NO_INIT) + mServiceState(SOUND_TRIGGER_STATE_NO_INIT) { } SoundTriggerHwService::Module::~Module() { + mModuleClients.clear(); } -void SoundTriggerHwService::Module::detach() { - ALOGV("detach()"); - if (!captureHotwordAllowed()) { +sp +SoundTriggerHwService::Module::addClient(const sp& client) +{ + AutoMutex lock(mLock); + sp moduleClient; + + for (size_t i = 0; i < mModuleClients.size(); i++) { + if (mModuleClients[i]->client() == client) { + // Client already present, reject client + return moduleClient; + } + } + moduleClient = new ModuleClient(this, client); + + ALOGV("addClient() client %p", moduleClient.get()); + mModuleClients.add(moduleClient); + + return moduleClient; +} + +void SoundTriggerHwService::Module::detach(const sp& moduleClient) +{ + ALOGV("Module::detach()"); + AutoMutex lock(mLock); + ssize_t index = -1; + + for (size_t i = 0; i < mModuleClients.size(); i++) { + if (mModuleClients[i] == moduleClient) { + index = i; + break; + } + } + if (index == -1) { return; } - { - AutoMutex lock(mLock); - for (size_t i = 0; i < mModels.size(); i++) { - sp model = mModels.valueAt(i); + + ALOGV("remove client %p", moduleClient.get()); + mModuleClients.removeAt(index); + + //iterate in reverse order as models are removed from list inside the loop + for (size_t i = mModels.size(); i > 0; i--) { + sp model = mModels.valueAt(i - 1); + if (moduleClient == model->mModuleClient) { + mModels.removeItemsAt(i - 1); ALOGV("detach() unloading model %d", model->mHandle); if (model->mState == Model::STATE_ACTIVE) { mHwDevice->stop_recognition(mHwDevice, model->mHandle); } + AudioSystem::releaseSoundTriggerSession(model->mCaptureSession); mHwDevice->unload_sound_model(mHwDevice, model->mHandle); } - mModels.clear(); - } - if (mClient != 0) { - IInterface::asBinder(mClient)->unlinkToDeath(this); - } - sp service = mService.promote(); - if (service == 0) { - return; } - service->detachModule(this); } status_t SoundTriggerHwService::Module::loadSoundModel(const sp& modelMemory, - sound_model_handle_t *handle) + sp moduleClient, + sound_model_handle_t *handle) { ALOGV("loadSoundModel() handle"); - if (!captureHotwordAllowed()) { - return PERMISSION_DENIED; - } - if (modelMemory == 0 || modelMemory->pointer() == NULL) { ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()"); return BAD_VALUE; @@ -613,7 +661,8 @@ status_t SoundTriggerHwService::Module::loadSoundModel(const sp& modelM return status; } - sp model = new Model(*handle, session, ioHandle, device, sound_model->type); + sp model = new Model(*handle, session, ioHandle, device, sound_model->type, + moduleClient); mModels.replaceValueFor(*handle, model); return status; @@ -622,10 +671,6 @@ status_t SoundTriggerHwService::Module::loadSoundModel(const sp& modelM status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle) { ALOGV("unloadSoundModel() model handle %d", handle); - if (!captureHotwordAllowed()) { - return PERMISSION_DENIED; - } - AutoMutex lock(mLock); return unloadSoundModel_l(handle); } @@ -650,10 +695,6 @@ status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t ha const sp& dataMemory) { ALOGV("startRecognition() model handle %d", handle); - if (!captureHotwordAllowed()) { - return PERMISSION_DENIED; - } - if (dataMemory == 0 || dataMemory->pointer() == NULL) { ALOGE("startRecognition() dataMemory is 0 or has NULL pointer()"); return BAD_VALUE; @@ -703,10 +744,6 @@ status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t ha status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle) { ALOGV("stopRecognition() model handle %d", handle); - if (!captureHotwordAllowed()) { - return PERMISSION_DENIED; - } - AutoMutex lock(mLock); sp model = getModel(handle); if (model == 0) { @@ -721,7 +758,6 @@ status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t han return NO_ERROR; } - void SoundTriggerHwService::Module::onCallbackEvent(const sp& event) { ALOGV("onCallbackEvent type %d", event->mType); @@ -731,8 +767,8 @@ void SoundTriggerHwService::Module::onCallbackEvent(const sp& eve if (eventMemory == 0 || eventMemory->pointer() == NULL) { return; } - if (mClient == 0) { - ALOGI("%s mClient == 0", __func__); + if (mModuleClients.isEmpty()) { + ALOGI("%s no clients", __func__); return; } @@ -755,7 +791,7 @@ void SoundTriggerHwService::Module::onCallbackEvent(const sp& eve recognitionEvent->capture_session = model->mCaptureSession; model->mState = Model::STATE_IDLE; - client = mClient; + client = model->mModuleClient->client(); } if (client != 0) { client->onRecognitionEvent(eventMemory); @@ -772,20 +808,24 @@ void SoundTriggerHwService::Module::onCallbackEvent(const sp& eve ALOGW("%s model == 0", __func__); return; } - client = mClient; + client = model->mModuleClient->client(); } if (client != 0) { client->onSoundModelEvent(eventMemory); } } break; case CallbackEvent::TYPE_SERVICE_STATE: { - sp client; + Vector< sp > clients; { AutoMutex lock(mLock); - client = mClient; + for (size_t i = 0; i < mModuleClients.size(); i++) { + if (mModuleClients[i] != 0) { + clients.add(mModuleClients[i]->client()); + } + } } - if (client != 0) { - client->onServiceStateChange(eventMemory); + for (size_t i = 0; i < clients.size(); i++) { + clients[i]->onServiceStateChange(eventMemory); } } break; default: @@ -804,12 +844,6 @@ sp SoundTriggerHwService::Module::getModel( return model; } -void SoundTriggerHwService::Module::binderDied( - const wp &who __unused) { - ALOGW("client binder died for module %d", mDescriptor.handle); - detach(); -} - // Called with mServiceLock held void SoundTriggerHwService::Module::setCaptureState_l(bool active) { @@ -898,8 +932,10 @@ void SoundTriggerHwService::Module::setCaptureState_l(bool active) } for (size_t i = 0; i < events.size(); i++) { - service->sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, events[i], - this)); + sp callbackEvent = new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, + events[i]); + callbackEvent->setModule(this); + service->sendCallbackEvent_l(callbackEvent); } exit: @@ -909,17 +945,171 @@ void SoundTriggerHwService::Module::setCaptureState_l(bool active) SoundTriggerHwService::Model::Model(sound_model_handle_t handle, audio_session_t session, audio_io_handle_t ioHandle, audio_devices_t device, - sound_trigger_sound_model_type_t type) : + sound_trigger_sound_model_type_t type, + sp& moduleClient) : mHandle(handle), mState(STATE_IDLE), mCaptureSession(session), - mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type) + mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type), + mModuleClient(moduleClient) { } -status_t SoundTriggerHwService::Module::dump(int fd __unused, - const Vector& args __unused) { +#undef LOG_TAG +#define LOG_TAG "SoundTriggerHwService::ModuleClient" + +SoundTriggerHwService::ModuleClient::ModuleClient(const sp& module, + const sp& client) + : mModule(module), mClient(client) +{ +} + +void SoundTriggerHwService::ModuleClient::onFirstRef() +{ + IInterface::asBinder(mClient)->linkToDeath(this); +} + +SoundTriggerHwService::ModuleClient::~ModuleClient() +{ +} + +status_t SoundTriggerHwService::ModuleClient::dump(int fd __unused, + const Vector& args __unused) { String8 result; return NO_ERROR; } +void SoundTriggerHwService::ModuleClient::detach() { + ALOGV("detach()"); + if (!captureHotwordAllowed()) { + return; + } + + { + AutoMutex lock(mLock); + if (mClient != 0) { + IInterface::asBinder(mClient)->unlinkToDeath(this); + mClient.clear(); + } + } + + sp module = mModule.promote(); + if (module == 0) { + return; + } + module->detach(this); +} + +status_t SoundTriggerHwService::ModuleClient::loadSoundModel(const sp& modelMemory, + sound_model_handle_t *handle) +{ + ALOGV("loadSoundModel() handle"); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + + sp module = mModule.promote(); + if (module == 0) { + return NO_INIT; + } + return module->loadSoundModel(modelMemory, this, handle); +} + +status_t SoundTriggerHwService::ModuleClient::unloadSoundModel(sound_model_handle_t handle) +{ + ALOGV("unloadSoundModel() model handle %d", handle); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + + sp module = mModule.promote(); + if (module == 0) { + return NO_INIT; + } + return module->unloadSoundModel(handle); +} + +status_t SoundTriggerHwService::ModuleClient::startRecognition(sound_model_handle_t handle, + const sp& dataMemory) +{ + ALOGV("startRecognition() model handle %d", handle); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + + sp module = mModule.promote(); + if (module == 0) { + return NO_INIT; + } + return module->startRecognition(handle, dataMemory); +} + +status_t SoundTriggerHwService::ModuleClient::stopRecognition(sound_model_handle_t handle) +{ + ALOGV("stopRecognition() model handle %d", handle); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + + sp module = mModule.promote(); + if (module == 0) { + return NO_INIT; + } + return module->stopRecognition(handle); +} + +void SoundTriggerHwService::ModuleClient::setCaptureState_l(bool active) +{ + ALOGV("ModuleClient::setCaptureState_l %d", active); + sp service; + sound_trigger_service_state_t state; + + sp module = mModule.promote(); + if (module == 0) { + return; + } + { + AutoMutex lock(mLock); + state = (active && !module->isConcurrentCaptureAllowed()) ? + SOUND_TRIGGER_STATE_DISABLED : SOUND_TRIGGER_STATE_ENABLED; + + service = module->service().promote(); + if (service == 0) { + return; + } + } + service->sendServiceStateEvent_l(state, this); +} + +void SoundTriggerHwService::ModuleClient::onCallbackEvent(const sp& event) +{ + ALOGV("ModuleClient onCallbackEvent type %d", event->mType); + + sp eventMemory = event->mMemory; + + if (eventMemory == 0 || eventMemory->pointer() == NULL) { + return; + } + + switch (event->mType) { + case CallbackEvent::TYPE_SERVICE_STATE: { + sp client; + { + AutoMutex lock(mLock); + client = mClient; + } + if (client !=0 ) { + client->onServiceStateChange(eventMemory); + } + } break; + default: + LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType); + } +} + +void SoundTriggerHwService::ModuleClient::binderDied( + const wp &who __unused) { + ALOGW("client binder died for client %p", this); + detach(); +} + }; // namespace android diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h index 2619a5fb4..fcb189dd0 100644 --- a/services/soundtrigger/SoundTriggerHwService.h +++ b/services/soundtrigger/SoundTriggerHwService.h @@ -39,6 +39,7 @@ class SoundTriggerHwService : friend class BinderService; public: class Module; + class ModuleClient; static char const* getServiceName() { return "media.sound_trigger_hw"; } @@ -69,7 +70,8 @@ class SoundTriggerHwService : }; Model(sound_model_handle_t handle, audio_session_t session, audio_io_handle_t ioHandle, - audio_devices_t device, sound_trigger_sound_model_type_t type); + audio_devices_t device, sound_trigger_sound_model_type_t type, + sp& moduleClient); ~Model() {} sound_model_handle_t mHandle; @@ -79,6 +81,7 @@ class SoundTriggerHwService : audio_devices_t mCaptureDevice; sound_trigger_sound_model_type_t mType; struct sound_trigger_recognition_config mConfig; + sp mModuleClient; }; class CallbackEvent : public RefBase { @@ -88,30 +91,30 @@ class SoundTriggerHwService : TYPE_SOUNDMODEL, TYPE_SERVICE_STATE, } event_type; - CallbackEvent(event_type type, sp memory, wp module); + CallbackEvent(event_type type, sp memory); virtual ~CallbackEvent(); + void setModule(wp module) { mModule = module; } + void setModuleClient(wp moduleClient) { mModuleClient = moduleClient; } + event_type mType; sp mMemory; wp mModule; + wp mModuleClient; }; - class Module : public virtual RefBase, - public BnSoundTrigger, - public IBinder::DeathRecipient { + class Module : public RefBase { public: Module(const sp& service, sound_trigger_hw_device* hwDevice, - sound_trigger_module_descriptor descriptor, - const sp& client); + sound_trigger_module_descriptor descriptor); virtual ~Module(); - virtual void detach(); - virtual status_t loadSoundModel(const sp& modelMemory, + sp moduleClient, sound_model_handle_t *handle); virtual status_t unloadSoundModel(sound_model_handle_t handle); @@ -120,39 +123,75 @@ class SoundTriggerHwService : const sp& dataMemory); virtual status_t stopRecognition(sound_model_handle_t handle); - virtual status_t dump(int fd, const Vector& args); - - sound_trigger_hw_device *hwDevice() const { return mHwDevice; } struct sound_trigger_module_descriptor descriptor() { return mDescriptor; } - void setClient(sp client) { mClient = client; } - void clearClient() { mClient.clear(); } - sp client() const { return mClient; } wp service() const { return mService; } - - void onCallbackEvent(const sp& event); + bool isConcurrentCaptureAllowed() const { return mDescriptor.properties.concurrent_capture; } sp getModel(sound_model_handle_t handle); void setCaptureState_l(bool active); - // IBinder::DeathRecipient implementation - virtual void binderDied(const wp &who); + sp addClient(const sp& client); - private: + void detach(const sp& moduleClient); + + void onCallbackEvent(const sp& event); - status_t unloadSoundModel_l(sound_model_handle_t handle); + private: + status_t unloadSoundModel_l(sound_model_handle_t handle); Mutex mLock; wp mService; struct sound_trigger_hw_device* mHwDevice; struct sound_trigger_module_descriptor mDescriptor; - sp mClient; + Vector< sp > mModuleClients; DefaultKeyedVector< sound_model_handle_t, sp > mModels; sound_trigger_service_state_t mServiceState; }; // class Module + class ModuleClient : public virtual RefBase, + public BnSoundTrigger, + public IBinder::DeathRecipient { + public: + + ModuleClient(const sp& module, + const sp& client); + + virtual ~ModuleClient(); + + virtual void detach(); + + virtual status_t loadSoundModel(const sp& modelMemory, + sound_model_handle_t *handle); + + virtual status_t unloadSoundModel(sound_model_handle_t handle); + + virtual status_t startRecognition(sound_model_handle_t handle, + const sp& dataMemory); + virtual status_t stopRecognition(sound_model_handle_t handle); + + virtual status_t dump(int fd, const Vector& args); + + virtual void onFirstRef(); + + // IBinder::DeathRecipient implementation + virtual void binderDied(const wp &who); + + void onCallbackEvent(const sp& event); + + void setCaptureState_l(bool active); + + sp client() const { return mClient; } + + private: + + mutable Mutex mLock; + wp mModule; + sp mClient; + }; // class ModuleClient + class CallbackThread : public Thread { public: @@ -176,8 +215,6 @@ class SoundTriggerHwService : Vector< sp > mEventQueue; }; - void detachModule(sp module); - static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie); sp prepareRecognitionEvent_l(struct sound_trigger_recognition_event *event); void sendRecognitionEvent(struct sound_trigger_recognition_event *event, Module *module); @@ -188,6 +225,8 @@ class SoundTriggerHwService : sp prepareServiceStateEvent_l(sound_trigger_service_state_t state); void sendServiceStateEvent_l(sound_trigger_service_state_t state, Module *module); + void sendServiceStateEvent_l(sound_trigger_service_state_t state, + ModuleClient *moduleClient); void sendCallbackEvent_l(const sp& event); void onCallbackEvent(const sp& event);