diff options
41 files changed, 1138 insertions, 429 deletions
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h index bfbc6bf..27df9cd 100644 --- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h +++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h @@ -104,6 +104,10 @@ public: return android::ERROR_DRM_CANNOT_HANDLE; } + virtual status_t unprovisionDevice() { + return android::ERROR_DRM_CANNOT_HANDLE; + } + virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops) { UNUSED(secureStops); return android::ERROR_DRM_CANNOT_HANDLE; diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp index 6efc712..2ea554b 100644 --- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp +++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp @@ -299,6 +299,12 @@ namespace android { return OK; } + status_t MockDrmPlugin::unprovisionDevice() + { + ALOGD("MockDrmPlugin::unprovisionDevice()"); + return OK; + } + status_t MockDrmPlugin::getSecureStops(List<Vector<uint8_t> > &secureStops) { Mutex::Autolock lock(mLock); diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h index 97d7052..4b63299 100644 --- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h +++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h @@ -85,6 +85,8 @@ namespace android { Vector<uint8_t> &certificate, Vector<uint8_t> &wrappedKey); + status_t unprovisionDevice(); + status_t getSecureStops(List<Vector<uint8_t> > &secureStops); status_t releaseSecureStops(Vector<uint8_t> const &ssRelease); diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index cf34991..f22792f 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -309,6 +309,12 @@ public: /* Set audio port configuration */ static status_t setAudioPortConfig(const struct audio_port_config *config); + + static status_t acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device); + static status_t releaseSoundTriggerSession(audio_session_t session); + // ---------------------------------------------------------------------------- class AudioPortCallback : public RefBase diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h index abbda32..c251439 100644 --- a/include/media/IAudioPolicyService.h +++ b/include/media/IAudioPolicyService.h @@ -136,6 +136,12 @@ public: virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0; virtual void registerClient(const sp<IAudioPolicyServiceClient>& client) = 0; + + virtual status_t acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device) = 0; + + virtual status_t releaseSoundTriggerSession(audio_session_t session) = 0; }; diff --git a/include/media/IDrm.h b/include/media/IDrm.h index 32ae28e..68de87a 100644 --- a/include/media/IDrm.h +++ b/include/media/IDrm.h @@ -70,6 +70,8 @@ struct IDrm : public IInterface { Vector<uint8_t> &certificate, Vector<uint8_t> &wrappedKey) = 0; + virtual status_t unprovisionDevice() = 0; + virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0; virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0; diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h index 4b18a0b..e1b2830 100644 --- a/include/media/stagefright/MediaCodecSource.h +++ b/include/media/stagefright/MediaCodecSource.h @@ -106,7 +106,6 @@ private: bool mStarted; bool mStopping; bool mDoMoreWorkPending; - bool mPullerReachedEOS; sp<AMessage> mEncoderActivityNotify; sp<IGraphicBufferProducer> mGraphicBufferProducer; Vector<sp<ABuffer> > mEncoderInputBuffers; @@ -123,7 +122,7 @@ private: Mutex mOutputBufferLock; Condition mOutputBufferCond; List<MediaBuffer*> mOutputBufferQueue; - bool mEncodedReachedEOS; + bool mEncoderReachedEOS; status_t mErrorCode; DISALLOW_EVIL_CONSTRUCTORS(MediaCodecSource); diff --git a/include/soundtrigger/ISoundTriggerClient.h b/include/soundtrigger/ISoundTriggerClient.h index 7f86d02..480429a 100644 --- a/include/soundtrigger/ISoundTriggerClient.h +++ b/include/soundtrigger/ISoundTriggerClient.h @@ -31,6 +31,10 @@ public: virtual void onRecognitionEvent(const sp<IMemory>& eventMemory) = 0; + virtual void onSoundModelEvent(const sp<IMemory>& eventMemory) = 0; + + virtual void onServiceStateChange(const sp<IMemory>& eventMemory) = 0; + }; // ---------------------------------------------------------------------------- diff --git a/include/soundtrigger/ISoundTriggerHwService.h b/include/soundtrigger/ISoundTriggerHwService.h index 05a764a..ae0cb01 100644 --- a/include/soundtrigger/ISoundTriggerHwService.h +++ b/include/soundtrigger/ISoundTriggerHwService.h @@ -39,6 +39,8 @@ public: virtual status_t attach(const sound_trigger_module_handle_t handle, const sp<ISoundTriggerClient>& client, sp<ISoundTrigger>& module) = 0; + + virtual status_t setCaptureState(bool active) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h index 1f7f286..bf5e1de 100644 --- a/include/soundtrigger/SoundTrigger.h +++ b/include/soundtrigger/SoundTrigger.h @@ -18,6 +18,7 @@ #define ANDROID_HARDWARE_SOUNDTRIGGER_H #include <binder/IBinder.h> +#include <utils/threads.h> #include <soundtrigger/SoundTriggerCallback.h> #include <soundtrigger/ISoundTrigger.h> #include <soundtrigger/ISoundTriggerHwService.h> @@ -32,12 +33,15 @@ class SoundTrigger : public BnSoundTriggerClient, public IBinder::DeathRecipient { public: + + virtual ~SoundTrigger(); + static status_t listModules(struct sound_trigger_module_descriptor *modules, uint32_t *numModules); static sp<SoundTrigger> attach(const sound_trigger_module_handle_t module, const sp<SoundTriggerCallback>& callback); - virtual ~SoundTrigger(); + static status_t setCaptureState(bool active); void detach(); @@ -51,6 +55,8 @@ public: // BpSoundTriggerClient virtual void onRecognitionEvent(const sp<IMemory>& eventMemory); + virtual void onSoundModelEvent(const sp<IMemory>& eventMemory); + virtual void onServiceStateChange(const sp<IMemory>& eventMemory); //IBinder::DeathRecipient virtual void binderDied(const wp<IBinder>& who); diff --git a/include/soundtrigger/SoundTriggerCallback.h b/include/soundtrigger/SoundTriggerCallback.h index 8a5ba02..b5277f2 100644 --- a/include/soundtrigger/SoundTriggerCallback.h +++ b/include/soundtrigger/SoundTriggerCallback.h @@ -31,6 +31,10 @@ public: virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event) = 0; + virtual void onSoundModelEvent(struct sound_trigger_model_event *event) = 0; + + virtual void onServiceStateChange(sound_trigger_service_state_t state) = 0; + virtual void onServiceDied() = 0; }; diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 365a594..172b056 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -913,6 +913,21 @@ void AudioSystem::setAudioPortCallback(sp<AudioPortCallback> callBack) gAudioPortCallback = callBack; } +status_t AudioSystem::acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->acquireSoundTriggerSession(session, ioHandle, device); +} + +status_t AudioSystem::releaseSoundTriggerSession(audio_session_t session) +{ + const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) return PERMISSION_DENIED; + return aps->releaseSoundTriggerSession(session); +} // --------------------------------------------------------------------------- void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused) diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index 1593b17..b57f747 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -65,7 +65,9 @@ enum { LIST_AUDIO_PATCHES, SET_AUDIO_PORT_CONFIG, REGISTER_CLIENT, - GET_OUTPUT_FOR_ATTR + GET_OUTPUT_FOR_ATTR, + ACQUIRE_SOUNDTRIGGER_SESSION, + RELEASE_SOUNDTRIGGER_SESSION }; class BpAudioPolicyService : public BpInterface<IAudioPolicyService> @@ -563,6 +565,7 @@ public: } return status; } + virtual void registerClient(const sp<IAudioPolicyServiceClient>& client) { Parcel data, reply; @@ -570,6 +573,40 @@ public: data.writeStrongBinder(client->asBinder()); remote()->transact(REGISTER_CLIENT, data, &reply); } + + virtual status_t acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device) + { + if (session == NULL || ioHandle == NULL || device == NULL) { + return BAD_VALUE; + } + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + status_t status = remote()->transact(ACQUIRE_SOUNDTRIGGER_SESSION, data, &reply); + if (status != NO_ERROR) { + return status; + } + status = (status_t)reply.readInt32(); + if (status == NO_ERROR) { + *session = (audio_session_t)reply.readInt32(); + *ioHandle = (audio_io_handle_t)reply.readInt32(); + *device = (audio_devices_t)reply.readInt32(); + } + return status; + } + + virtual status_t releaseSoundTriggerSession(audio_session_t session) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeInt32(session); + status_t status = remote()->transact(RELEASE_SOUNDTRIGGER_SESSION, data, &reply); + if (status != NO_ERROR) { + return status; + } + return (status_t)reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -984,6 +1021,7 @@ status_t BnAudioPolicyService::onTransact( reply->writeInt32(status); return NO_ERROR; } + case REGISTER_CLIENT: { CHECK_INTERFACE(IAudioPolicyService, data, reply); sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>( @@ -992,6 +1030,33 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } break; + case ACQUIRE_SOUNDTRIGGER_SESSION: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>( + data.readStrongBinder()); + audio_session_t session; + audio_io_handle_t ioHandle; + audio_devices_t device; + status_t status = acquireSoundTriggerSession(&session, &ioHandle, &device); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeInt32(session); + reply->writeInt32(ioHandle); + reply->writeInt32(device); + } + return NO_ERROR; + } break; + + case RELEASE_SOUNDTRIGGER_SESSION: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + sp<IAudioPolicyServiceClient> client = interface_cast<IAudioPolicyServiceClient>( + data.readStrongBinder()); + audio_session_t session = (audio_session_t)data.readInt32(); + status_t status = releaseSoundTriggerSession(session); + reply->writeInt32(status); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp index f1a6a9f..1904839 100644 --- a/media/libmedia/IDrm.cpp +++ b/media/libmedia/IDrm.cpp @@ -53,7 +53,8 @@ enum { SIGN, SIGN_RSA, VERIFY, - SET_LISTENER + SET_LISTENER, + UNPROVISION_DEVICE }; struct BpDrm : public BpInterface<IDrm> { @@ -229,6 +230,15 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } + virtual status_t unprovisionDevice() { + Parcel data, reply; + data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); + + remote()->transact(UNPROVISION_DEVICE, data, &reply); + + return reply.readInt32(); + } + virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) { Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); @@ -619,6 +629,14 @@ status_t BnDrm::onTransact( return OK; } + case UNPROVISION_DEVICE: + { + CHECK_INTERFACE(IDrm, data, reply); + status_t result = unprovisionDevice(); + reply->writeInt32(result); + return OK; + } + case GET_SECURE_STOPS: { CHECK_INTERFACE(IDrm, data, reply); diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp index d50037f..d222316 100644 --- a/media/libmediaplayerservice/Drm.cpp +++ b/media/libmediaplayerservice/Drm.cpp @@ -417,6 +417,23 @@ status_t Drm::provideProvisionResponse(Vector<uint8_t> const &response, return mPlugin->provideProvisionResponse(response, certificate, wrappedKey); } +status_t Drm::unprovisionDevice() { + Mutex::Autolock autoLock(mLock); + + if (mInitCheck != OK) { + return mInitCheck; + } + + if (mPlugin == NULL) { + return -EINVAL; + } + + if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) { + return -EPERM; + } + + return mPlugin->unprovisionDevice(); +} status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) { Mutex::Autolock autoLock(mLock); diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h index 3d4b0fc..9e23e2e 100644 --- a/media/libmediaplayerservice/Drm.h +++ b/media/libmediaplayerservice/Drm.h @@ -75,6 +75,8 @@ struct Drm : public BnDrm, Vector<uint8_t> &certificate, Vector<uint8_t> &wrappedKey); + virtual status_t unprovisionDevice(); + virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops); virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 2f5b0f1..32842bb 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -14,6 +14,9 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 +#define LOG_TAG "GenericSource" + #include "GenericSource.h" #include "AnotherPacketSource.h" @@ -42,6 +45,7 @@ NuPlayer::GenericSource::GenericSource( uid_t uid) : Source(notify), mFetchSubtitleDataGeneration(0), + mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), mIsWidevine(isWidevine), @@ -61,9 +65,12 @@ NuPlayer::GenericSource::GenericSource( int fd, int64_t offset, int64_t length) : Source(notify), mFetchSubtitleDataGeneration(0), + mFetchTimedTextDataGeneration(0), mDurationUs(0ll), mAudioIsVorbis(false), - mIsWidevine(false) { + mIsWidevine(false), + mUIDValid(false), + mUID(0) { DataSource::RegisterDefaultSniffers(); sp<DataSource> dataSource = new FileSource(dup(fd), offset, length); @@ -132,6 +139,12 @@ void NuPlayer::GenericSource::initFromDataSource( if (mVideoTrack.mSource == NULL) { mVideoTrack.mIndex = i; mVideoTrack.mSource = track; + + // check if the source requires secure buffers + int32_t secure; + if (meta->findInt32(kKeyRequiresSecureBuffers, &secure) && secure) { + mIsWidevine = true; + } } } @@ -206,66 +219,29 @@ void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatFetchSubtitleData: { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - if (generation != mFetchSubtitleDataGeneration) { - // stale - break; - } - - int32_t avail; - if (mSubtitleTrack.mPackets->hasBufferAvailable(&avail)) { - break; - } - - int64_t timeUs; - CHECK(msg->findInt64("timeUs", &timeUs)); - - int64_t subTimeUs; - readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, timeUs, &subTimeUs); - - const int64_t oneSecUs = 1000000ll; - const int64_t delayUs = subTimeUs - timeUs - oneSecUs; - sp<AMessage> msg2 = new AMessage(kWhatSendSubtitleData, id()); - msg2->setInt32("generation", generation); - msg2->post(delayUs < 0 ? 0 : delayUs); - ALOGV("kWhatFetchSubtitleData generation %d, delayUs %lld", - mFetchSubtitleDataGeneration, delayUs); + fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, + mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); + break; + } + case kWhatFetchTimedTextData: + { + fetchTextData(kWhatSendTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, + mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); break; } case kWhatSendSubtitleData: { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - if (generation != mFetchSubtitleDataGeneration) { - // stale - break; - } - - int64_t subTimeUs; - if (mSubtitleTrack.mPackets->nextBufferTime(&subTimeUs) != OK) { - break; - } - - int64_t nextSubTimeUs; - readBuffer(MEDIA_TRACK_TYPE_SUBTITLE, -1, &nextSubTimeUs); - - sp<ABuffer> buffer; - status_t dequeueStatus = mSubtitleTrack.mPackets->dequeueAccessUnit(&buffer); - if (dequeueStatus != OK) { - ALOGE("kWhatSendSubtitleData dequeueAccessUnit: %d", dequeueStatus); - } else { - sp<AMessage> notify = dupNotify(); - notify->setInt32("what", kWhatSubtitleData); - notify->setBuffer("buffer", buffer); - notify->post(); - - const int64_t delayUs = nextSubTimeUs - subTimeUs; - msg->post(delayUs < 0 ? 0 : delayUs); - } + sendTextData(kWhatSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE, + mFetchSubtitleDataGeneration, mSubtitleTrack.mPackets, msg); + break; + } + case kWhatSendTimedTextData: + { + sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT, + mFetchTimedTextDataGeneration, mTimedTextTrack.mPackets, msg); break; } @@ -323,6 +299,74 @@ void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { } } +void NuPlayer::GenericSource::fetchTextData( + uint32_t sendWhat, + media_track_type type, + int32_t curGen, + sp<AnotherPacketSource> packets, + sp<AMessage> msg) { + int32_t msgGeneration; + CHECK(msg->findInt32("generation", &msgGeneration)); + if (msgGeneration != curGen) { + // stale + return; + } + + int32_t avail; + if (packets->hasBufferAvailable(&avail)) { + return; + } + + int64_t timeUs; + CHECK(msg->findInt64("timeUs", &timeUs)); + + int64_t subTimeUs; + readBuffer(type, timeUs, &subTimeUs); + + int64_t delayUs = subTimeUs - timeUs; + if (msg->what() == kWhatFetchSubtitleData) { + const int64_t oneSecUs = 1000000ll; + delayUs -= oneSecUs; + } + sp<AMessage> msg2 = new AMessage(sendWhat, id()); + msg2->setInt32("generation", msgGeneration); + msg2->post(delayUs < 0 ? 0 : delayUs); +} + +void NuPlayer::GenericSource::sendTextData( + uint32_t what, + media_track_type type, + int32_t curGen, + sp<AnotherPacketSource> packets, + sp<AMessage> msg) { + int32_t msgGeneration; + CHECK(msg->findInt32("generation", &msgGeneration)); + if (msgGeneration != curGen) { + // stale + return; + } + + int64_t subTimeUs; + if (packets->nextBufferTime(&subTimeUs) != OK) { + return; + } + + int64_t nextSubTimeUs; + readBuffer(type, -1, &nextSubTimeUs); + + sp<ABuffer> buffer; + status_t dequeueStatus = packets->dequeueAccessUnit(&buffer); + if (dequeueStatus == OK) { + sp<AMessage> notify = dupNotify(); + notify->setInt32("what", what); + notify->setBuffer("buffer", buffer); + notify->post(); + + const int64_t delayUs = nextSubTimeUs - subTimeUs; + msg->post(delayUs < 0 ? 0 : delayUs); + } +} + sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) { sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource; @@ -357,27 +401,49 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( readBuffer(audio? MEDIA_TRACK_TYPE_AUDIO : MEDIA_TRACK_TYPE_VIDEO, -1ll); } - if (mSubtitleTrack.mSource == NULL) { + if (mSubtitleTrack.mSource == NULL && mTimedTextTrack.mSource == NULL) { return result; } - CHECK(mSubtitleTrack.mPackets != NULL); + if (mSubtitleTrack.mSource != NULL) { + CHECK(mSubtitleTrack.mPackets != NULL); + } + if (mTimedTextTrack.mSource != NULL) { + CHECK(mTimedTextTrack.mPackets != NULL); + } + if (result != OK) { - mSubtitleTrack.mPackets->clear(); - mFetchSubtitleDataGeneration++; + if (mSubtitleTrack.mSource != NULL) { + mSubtitleTrack.mPackets->clear(); + mFetchSubtitleDataGeneration++; + } + if (mTimedTextTrack.mSource != NULL) { + mTimedTextTrack.mPackets->clear(); + mFetchTimedTextDataGeneration++; + } return result; } int64_t timeUs; status_t eosResult; // ignored CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); - if (!mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { + + if (mSubtitleTrack.mSource != NULL + && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) { sp<AMessage> msg = new AMessage(kWhatFetchSubtitleData, id()); msg->setInt64("timeUs", timeUs); msg->setInt32("generation", mFetchSubtitleDataGeneration); msg->post(); } + if (mTimedTextTrack.mSource != NULL + && !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) { + sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, id()); + msg->setInt64("timeUs", timeUs); + msg->setInt32("generation", mFetchTimedTextDataGeneration); + msg->post(); + } + return result; } @@ -436,20 +502,53 @@ sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { return format; } +ssize_t NuPlayer::GenericSource::getSelectedTrack(media_track_type type) const { + const Track *track = NULL; + switch (type) { + case MEDIA_TRACK_TYPE_VIDEO: + track = &mVideoTrack; + break; + case MEDIA_TRACK_TYPE_AUDIO: + track = &mAudioTrack; + break; + case MEDIA_TRACK_TYPE_TIMEDTEXT: + track = &mTimedTextTrack; + break; + case MEDIA_TRACK_TYPE_SUBTITLE: + track = &mSubtitleTrack; + break; + default: + break; + } + + if (track != NULL && track->mSource != NULL) { + return track->mIndex; + } + + return -1; +} + status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { - ALOGV("selectTrack: %zu", trackIndex); + ALOGV("%s track: %zu", select ? "select" : "deselect", trackIndex); if (trackIndex >= mSources.size()) { return BAD_INDEX; } if (!select) { - if (mSubtitleTrack.mSource == NULL || trackIndex != mSubtitleTrack.mIndex) { + Track* track = NULL; + if (mSubtitleTrack.mSource != NULL && trackIndex == mSubtitleTrack.mIndex) { + track = &mSubtitleTrack; + mFetchSubtitleDataGeneration++; + } else if (mTimedTextTrack.mSource != NULL && trackIndex == mTimedTextTrack.mIndex) { + track = &mTimedTextTrack; + mFetchTimedTextDataGeneration++; + } + if (track == NULL) { return INVALID_OPERATION; } - mSubtitleTrack.mSource->stop(); - mSubtitleTrack.mSource = NULL; - mSubtitleTrack.mPackets->clear(); - mFetchSubtitleDataGeneration++; + track->mSource->stop(); + track->mSource = NULL; + track->mPackets->clear(); return OK; } @@ -458,22 +557,31 @@ status_t NuPlayer::GenericSource::selectTrack(size_t trackIndex, bool select) { const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); if (!strncasecmp(mime, "text/", 5)) { - if (mSubtitleTrack.mSource != NULL && mSubtitleTrack.mIndex == trackIndex) { + bool isSubtitle = strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP); + Track *track = isSubtitle ? &mSubtitleTrack : &mTimedTextTrack; + if (track->mSource != NULL && track->mIndex == trackIndex) { return OK; } - mSubtitleTrack.mIndex = trackIndex; - if (mSubtitleTrack.mSource != NULL) { - mSubtitleTrack.mSource->stop(); + track->mIndex = trackIndex; + if (track->mSource != NULL) { + track->mSource->stop(); } - mSubtitleTrack.mSource = mSources.itemAt(trackIndex); - mSubtitleTrack.mSource->start(); - if (mSubtitleTrack.mPackets == NULL) { - mSubtitleTrack.mPackets = new AnotherPacketSource(mSubtitleTrack.mSource->getFormat()); + track->mSource = mSources.itemAt(trackIndex); + track->mSource->start(); + if (track->mPackets == NULL) { + track->mPackets = new AnotherPacketSource(track->mSource->getFormat()); } else { - mSubtitleTrack.mPackets->clear(); + track->mPackets->clear(); + track->mPackets->setFormat(track->mSource->getFormat()); + + } + if (isSubtitle) { + mFetchSubtitleDataGeneration++; + } else { + mFetchTimedTextDataGeneration++; } - mFetchSubtitleDataGeneration++; + return OK; } else if (!strncasecmp(mime, "audio/", 6) || !strncasecmp(mime, "video/", 6)) { bool audio = !strncasecmp(mime, "audio/", 6); @@ -540,12 +648,19 @@ sp<ABuffer> NuPlayer::GenericSource::mediaBufferToABuffer( memcpy(abEnd, &numPageSamples, sizeof(numPageSamples)); } + sp<AMessage> meta = ab->meta(); + int64_t timeUs; CHECK(mb->meta_data()->findInt64(kKeyTime, &timeUs)); - - sp<AMessage> meta = ab->meta(); meta->setInt64("timeUs", timeUs); + if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) { + const char *mime; + CHECK(mTimedTextTrack.mSource != NULL + && mTimedTextTrack.mSource->getFormat()->findCString(kKeyMIMEType, &mime)); + meta->setString("mime", mime); + } + int64_t durationUs; if (mb->meta_data()->findInt64(kKeyDuration, &durationUs)) { meta->setInt64("durationUs", durationUs); @@ -578,6 +693,9 @@ void NuPlayer::GenericSource::readBuffer( case MEDIA_TRACK_TYPE_SUBTITLE: track = &mSubtitleTrack; break; + case MEDIA_TRACK_TYPE_TIMEDTEXT: + track = &mTimedTextTrack; + break; default: TRESPASS(); } @@ -613,7 +731,9 @@ void NuPlayer::GenericSource::readBuffer( // formatChange && seeking: track whose source is changed during selection // formatChange && !seeking: track whose source is not changed during selection // !formatChange: normal seek - if ((seeking || formatChange) && trackType != MEDIA_TRACK_TYPE_SUBTITLE) { + if ((seeking || formatChange) + && (trackType == MEDIA_TRACK_TYPE_AUDIO + || trackType == MEDIA_TRACK_TYPE_VIDEO)) { ATSParser::DiscontinuityType type = formatChange ? (seeking ? ATSParser::DISCONTINUITY_FORMATCHANGE diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h index 4e25d55..3c5f55c 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.h +++ b/media/libmediaplayerservice/nuplayer/GenericSource.h @@ -58,6 +58,7 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual status_t getDuration(int64_t *durationUs); virtual size_t getTrackCount() const; virtual sp<AMessage> getTrackInfo(size_t trackIndex) const; + virtual ssize_t getSelectedTrack(media_track_type type) const; virtual status_t selectTrack(size_t trackIndex, bool select); virtual status_t seekTo(int64_t seekTimeUs); @@ -73,7 +74,9 @@ protected: private: enum { kWhatFetchSubtitleData, + kWhatFetchTimedTextData, kWhatSendSubtitleData, + kWhatSendTimedTextData, kWhatChangeAVSource, }; @@ -88,8 +91,10 @@ private: Track mAudioTrack; Track mVideoTrack; Track mSubtitleTrack; + Track mTimedTextTrack; int32_t mFetchSubtitleDataGeneration; + int32_t mFetchTimedTextDataGeneration; int64_t mDurationUs; bool mAudioIsVorbis; bool mIsWidevine; @@ -98,6 +103,14 @@ private: void initFromDataSource(const sp<DataSource> &dataSource); + void fetchTextData( + uint32_t what, media_track_type type, + int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg); + + void sendTextData( + uint32_t what, media_track_type type, + int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg); + sp<ABuffer> mediaBufferToABuffer( MediaBuffer *mbuf, media_track_type trackType, diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index 58d0138..17038a4 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -227,7 +227,9 @@ void NuPlayer::setDataSourceAsync( } else if ((!strncasecmp(url, "widevine://", 11))) { source = new GenericSource(notify, httpService, url, headers, true /* isWidevine */, mUIDValid, mUID); - mSourceFlags |= Source::FLAG_SECURE; + // Don't set FLAG_SECURE on mSourceFlags here, the correct flags + // will be updated in Source::kWhatFlagsChanged handler when + // GenericSource is prepared. } else { source = new GenericSource(notify, httpService, url, headers); } @@ -749,6 +751,15 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { ALOGV("Mime \"%s\" mapped to audio_format 0x%x", mime.c_str(), audioFormat); + int32_t aacProfile = -1; + if (audioFormat == AUDIO_FORMAT_AAC + && format->findInt32("aac-profile", &aacProfile)) { + // Redefine AAC format as per aac profile + mapAACProfileToAudioFormat( + audioFormat, + aacProfile); + } + flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD; offloadInfo.duration_us = -1; @@ -1169,11 +1180,11 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) { sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); - if ((audio && IsFlushingState(mFlushingAudio)) - || (!audio && IsFlushingState(mFlushingVideo))) { - reply->setInt32("err", INFO_DISCONTINUITY); - reply->post(); - return OK; + if ((audio && mFlushingAudio != NONE + && mFlushingAudio != AWAITING_DISCONTINUITY) + || (!audio && mFlushingVideo != NONE + && mFlushingVideo != AWAITING_DISCONTINUITY)) { + return -EWOULDBLOCK; } sp<ABuffer> accessUnit; diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index a67fabe..804f131 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -155,12 +155,12 @@ status_t AudioSource::reset() { } mStarted = false; + mFrameAvailableCondition.signal(); + mRecord->stop(); waitOutstandingEncodingFrames_l(); releaseQueuedFrames_l(); - mFrameAvailableCondition.signal(); - return OK; } diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp index 9868ecf..1a80dcc 100644 --- a/media/libstagefright/MediaCodecSource.cpp +++ b/media/libstagefright/MediaCodecSource.cpp @@ -54,7 +54,7 @@ struct MediaCodecSource::Puller : public AHandler { Puller(const sp<MediaSource> &source); status_t start(const sp<MetaData> &meta, const sp<AMessage> ¬ify); - void stopAsync(); + void stop(); void pause(); void resume(); @@ -139,8 +139,17 @@ status_t MediaCodecSource::Puller::start(const sp<MetaData> &meta, return postSynchronouslyAndReturnError(msg); } -void MediaCodecSource::Puller::stopAsync() { - ALOGV("puller (%s) stopAsync", mIsAudio ? "audio" : "video"); +void MediaCodecSource::Puller::stop() { + // Stop source from caller's thread instead of puller's looper. + // mSource->stop() is thread-safe, doing it outside the puller's + // looper allows us to at least stop if source gets stuck. + // If source gets stuck in read(), the looper would never + // be able to process the stop(), which could lead to ANR. + + ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video"); + mSource->stop(); + ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video"); + (new AMessage(kWhatStop, id()))->post(); } @@ -194,9 +203,6 @@ void MediaCodecSource::Puller::onMessageReceived(const sp<AMessage> &msg) { case kWhatStop: { - ALOGV("source (%s) stopping", mIsAudio ? "audio" : "video"); - mSource->stop(); - ALOGV("source (%s) stopped", mIsAudio ? "audio" : "video"); ++mPullGeneration; handleEOS(); @@ -283,7 +289,21 @@ status_t MediaCodecSource::start(MetaData* params) { status_t MediaCodecSource::stop() { sp<AMessage> msg = new AMessage(kWhatStop, mReflector->id()); - return postSynchronouslyAndReturnError(msg); + status_t err = postSynchronouslyAndReturnError(msg); + + // mPuller->stop() needs to be done outside MediaCodecSource's looper, + // as it contains a synchronous call to stop the underlying MediaSource, + // which often waits for all outstanding MediaBuffers to return, but + // MediaBuffers are only returned when MediaCodecSource looper gets + // to process them. + + if (mPuller != NULL) { + ALOGI("puller (%s) stopping", mIsVideo ? "video" : "audio"); + mPuller->stop(); + ALOGI("puller (%s) stopped", mIsVideo ? "video" : "audio"); + } + + return err; } status_t MediaCodecSource::pause() { @@ -301,10 +321,10 @@ status_t MediaCodecSource::read( Mutex::Autolock autolock(mOutputBufferLock); *buffer = NULL; - while (mOutputBufferQueue.size() == 0 && !mEncodedReachedEOS) { + while (mOutputBufferQueue.size() == 0 && !mEncoderReachedEOS) { mOutputBufferCond.wait(mOutputBufferLock); } - if (!mEncodedReachedEOS) { + if (!mEncoderReachedEOS) { *buffer = *mOutputBufferQueue.begin(); mOutputBufferQueue.erase(mOutputBufferQueue.begin()); return OK; @@ -330,9 +350,8 @@ MediaCodecSource::MediaCodecSource( mStarted(false), mStopping(false), mDoMoreWorkPending(false), - mPullerReachedEOS(false), mFirstSampleTimeUs(-1ll), - mEncodedReachedEOS(false), + mEncoderReachedEOS(false), mErrorCode(OK) { CHECK(mLooper != NULL); @@ -434,7 +453,7 @@ status_t MediaCodecSource::initEncoder() { return err; } - mEncodedReachedEOS = false; + mEncoderReachedEOS = false; mErrorCode = OK; return OK; @@ -465,10 +484,6 @@ void MediaCodecSource::releaseEncoder() { mEncoderOutputBuffers.clear(); } -bool MediaCodecSource::reachedEOS() { - return mEncodedReachedEOS && ((mPuller == NULL) || mPullerReachedEOS); -} - status_t MediaCodecSource::postSynchronouslyAndReturnError( const sp<AMessage> &msg) { sp<AMessage> response; @@ -486,8 +501,8 @@ status_t MediaCodecSource::postSynchronouslyAndReturnError( } void MediaCodecSource::signalEOS(status_t err) { - if (!mEncodedReachedEOS) { - ALOGI("encoder (%s) reached EOS", mIsVideo ? "video" : "audio"); + if (!mEncoderReachedEOS) { + ALOGV("encoder (%s) reached EOS", mIsVideo ? "video" : "audio"); { Mutex::Autolock autoLock(mOutputBufferLock); // release all unread media buffers @@ -496,16 +511,15 @@ void MediaCodecSource::signalEOS(status_t err) { (*it)->release(); } mOutputBufferQueue.clear(); - mEncodedReachedEOS = true; + mEncoderReachedEOS = true; mErrorCode = err; mOutputBufferCond.signal(); } releaseEncoder(); } - if (mStopping && reachedEOS()) { - ALOGI("MediaCodecSource (%s) fully stopped", - mIsVideo ? "video" : "audio"); + if (mStopping && mEncoderReachedEOS) { + ALOGI("encoder (%s) stopped", mIsVideo ? "video" : "audio"); // posting reply to everyone that's waiting List<uint32_t>::iterator it; for (it = mStopReplyIDQueue.begin(); @@ -755,7 +769,6 @@ status_t MediaCodecSource::onStart(MetaData *params) { kWhatPullerNotify, mReflector->id()); err = mPuller->start(params, notify); if (err != OK) { - mPullerReachedEOS = true; return err; } } @@ -774,9 +787,9 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { CHECK(msg->findPointer("accessUnit", (void**)&mbuf)); if (mbuf == NULL) { - ALOGI("puller (%s) reached EOS", + ALOGV("puller (%s) reached EOS", mIsVideo ? "video" : "audio"); - mPullerReachedEOS = true; + signalEOS(); } if (mEncoder == NULL) { @@ -785,9 +798,8 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { if (mbuf != NULL) { mbuf->release(); - } else { - signalEOS(); } + break; } @@ -833,14 +845,14 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { } case kWhatStop: { - ALOGI("MediaCodecSource (%s) stopping", mIsVideo ? "video" : "audio"); + ALOGI("encoder (%s) stopping", mIsVideo ? "video" : "audio"); uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - if (reachedEOS()) { + if (mEncoderReachedEOS) { // if we already reached EOS, reply and return now - ALOGI("MediaCodecSource (%s) already stopped", + ALOGI("encoder (%s) already stopped", mIsVideo ? "video" : "audio"); (new AMessage)->postReply(replyID); break; @@ -860,8 +872,6 @@ void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) { if (mFlags & FLAG_USE_SURFACE_INPUT) { mEncoder->signalEndOfInputStream(); } else { - CHECK(mPuller != NULL); - mPuller->stopAsync(); signalEOS(); } break; diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 587e264..5f1d1c6 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -135,6 +135,11 @@ status_t convertMetaDataToMessage( if (meta->findInt32(kKeyIsADTS, &isADTS)) { msg->setInt32("is-adts", true); } + + int32_t aacProfile = -1; + if (meta->findInt32(kKeyAACAOT, &aacProfile)) { + msg->setInt32("aac-profile", aacProfile); + } } int32_t maxInputSize; diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index bd7121e..b8cc33a 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1159,6 +1159,9 @@ status_t AudioFlinger::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrame void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client) { Mutex::Autolock _l(mLock); + if (client == 0) { + return; + } bool clientAdded = false; { Mutex::Autolock _cl(mClientLock); @@ -1453,6 +1456,9 @@ Exit: audio_module_handle_t AudioFlinger::loadHwModule(const char *name) { + if (name == NULL) { + return 0; + } if (!settingsAllowed()) { return 0; } diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index 6edca1b..7ac2c0c 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -1797,109 +1797,6 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, } } -#if 0 -// 2 tracks is also a common case -// NEVER used in current implementation of process__validate() -// only use if the 2 tracks have the same output buffer -void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, - int64_t pts) -{ - int i; - uint32_t en = state->enabledTracks; - - i = 31 - __builtin_clz(en); - const track_t& t0 = state->tracks[i]; - AudioBufferProvider::Buffer& b0(t0.buffer); - - en &= ~(1<<i); - i = 31 - __builtin_clz(en); - const track_t& t1 = state->tracks[i]; - AudioBufferProvider::Buffer& b1(t1.buffer); - - const int16_t *in0; - const int16_t vl0 = t0.volume[0]; - const int16_t vr0 = t0.volume[1]; - size_t frameCount0 = 0; - - const int16_t *in1; - const int16_t vl1 = t1.volume[0]; - const int16_t vr1 = t1.volume[1]; - size_t frameCount1 = 0; - - //FIXME: only works if two tracks use same buffer - int32_t* out = t0.mainBuffer; - size_t numFrames = state->frameCount; - const int16_t *buff = NULL; - - - while (numFrames) { - - if (frameCount0 == 0) { - b0.frameCount = numFrames; - int64_t outputPTS = calculateOutputPTS(t0, pts, - out - t0.mainBuffer); - t0.bufferProvider->getNextBuffer(&b0, outputPTS); - if (b0.i16 == NULL) { - if (buff == NULL) { - buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; - } - in0 = buff; - b0.frameCount = numFrames; - } else { - in0 = b0.i16; - } - frameCount0 = b0.frameCount; - } - if (frameCount1 == 0) { - b1.frameCount = numFrames; - int64_t outputPTS = calculateOutputPTS(t1, pts, - out - t0.mainBuffer); - t1.bufferProvider->getNextBuffer(&b1, outputPTS); - if (b1.i16 == NULL) { - if (buff == NULL) { - buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; - } - in1 = buff; - b1.frameCount = numFrames; - } else { - in1 = b1.i16; - } - frameCount1 = b1.frameCount; - } - - size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1; - - numFrames -= outFrames; - frameCount0 -= outFrames; - frameCount1 -= outFrames; - - do { - int32_t l0 = *in0++; - int32_t r0 = *in0++; - l0 = mul(l0, vl0); - r0 = mul(r0, vr0); - int32_t l = *in1++; - int32_t r = *in1++; - l = mulAdd(l, vl1, l0) >> 12; - r = mulAdd(r, vr1, r0) >> 12; - // clamping... - l = clamp16(l); - r = clamp16(r); - *out++ = (r<<16) | (l & 0xFFFF); - } while (--outFrames); - - if (frameCount0 == 0) { - t0.bufferProvider->releaseBuffer(&b0); - } - if (frameCount1 == 0) { - t1.bufferProvider->releaseBuffer(&b1); - } - } - - delete [] buff; -} -#endif - int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS, int outputFrameIndex) { diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h index 5ba377b..3b972bb 100644 --- a/services/audioflinger/AudioMixer.h +++ b/services/audioflinger/AudioMixer.h @@ -408,10 +408,6 @@ private: static void process__genericResampling(state_t* state, int64_t pts); static void process__OneTrack16BitsStereoNoResampling(state_t* state, int64_t pts); -#if 0 - static void process__TwoTracks16BitsStereoNoResampling(state_t* state, - int64_t pts); -#endif static int64_t calculateOutputPTS(const track_t& t, int64_t basePTS, int outputFrameIndex); diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp index 7e01c9f..40d7bcd 100644 --- a/services/audioflinger/StateQueue.cpp +++ b/services/audioflinger/StateQueue.cpp @@ -41,13 +41,14 @@ void StateQueueMutatorDump::dump(int fd) // Constructor and destructor template<typename T> StateQueue<T>::StateQueue() : - mNext(NULL), mAck(NULL), mCurrent(NULL), + mAck(NULL), mCurrent(NULL), mMutating(&mStates[0]), mExpecting(NULL), mInMutation(false), mIsDirty(false), mIsInitialized(false) #ifdef STATE_QUEUE_DUMP , mObserverDump(&mObserverDummyDump), mMutatorDump(&mMutatorDummyDump) #endif { + atomic_init(&mNext, 0); } template<typename T> StateQueue<T>::~StateQueue() @@ -58,11 +59,8 @@ template<typename T> StateQueue<T>::~StateQueue() template<typename T> const T* StateQueue<T>::poll() { -#ifdef __LP64__ - const T *next = (const T *) android_atomic_acquire_load64((volatile int64_t *) &mNext); -#else - const T *next = (const T *) android_atomic_acquire_load((volatile int32_t *) &mNext); -#endif + const T *next = (const T *) atomic_load_explicit(&mNext, memory_order_acquire); + if (next != mCurrent) { mAck = next; // no additional barrier needed mCurrent = next; @@ -144,11 +142,7 @@ template<typename T> bool StateQueue<T>::push(StateQueue<T>::block_t block) } // publish -#ifdef __LP64__ - android_atomic_release_store64((int64_t) mMutating, (volatile int64_t *) &mNext); -#else - android_atomic_release_store((int32_t) mMutating, (volatile int32_t *) &mNext); -#endif + atomic_store_explicit(&mNext, (uintptr_t)mMutating, memory_order_release); mExpecting = mMutating; // copy with circular wraparound diff --git a/services/audioflinger/StateQueue.h b/services/audioflinger/StateQueue.h index 9e176c4..27f6a28 100644 --- a/services/audioflinger/StateQueue.h +++ b/services/audioflinger/StateQueue.h @@ -17,6 +17,8 @@ #ifndef ANDROID_AUDIO_STATE_QUEUE_H #define ANDROID_AUDIO_STATE_QUEUE_H +#include <stdatomic.h> + // The state queue template class was originally driven by this use case / requirements: // There are two threads: a fast mixer, and a normal mixer, and they share state. // The interesting part of the shared state is a set of active fast tracks, @@ -186,7 +188,7 @@ private: T mStates[kN]; // written by mutator, read by observer // "volatile" is meaningless with SMP, but here it indicates that we're using atomic ops - volatile const T* mNext; // written by mutator to advance next, read by observer + atomic_uintptr_t mNext; // written by mutator to advance next, read by observer volatile const T* mAck; // written by observer to acknowledge advance of next, read by mutator // only used by observer diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk index f3be42d..6512c38 100644 --- a/services/audiopolicy/Android.mk +++ b/services/audiopolicy/Android.mk @@ -30,7 +30,7 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libmedia \ libhardware \ - libhardware_legacy \ + libhardware_legacy ifneq ($(USE_LEGACY_AUDIO_POLICY), 1) LOCAL_SHARED_LIBRARIES += \ @@ -58,7 +58,8 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ - liblog + liblog \ + libsoundtrigger LOCAL_STATIC_LIBRARIES := \ libmedia_helper diff --git a/services/audiopolicy/AudioPolicyClientImpl.cpp b/services/audiopolicy/AudioPolicyClientImpl.cpp index c0019d1..3e090e9 100644 --- a/services/audiopolicy/AudioPolicyClientImpl.cpp +++ b/services/audiopolicy/AudioPolicyClientImpl.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "AudioPolicyClientImpl" //#define LOG_NDEBUG 0 +#include <soundtrigger/SoundTrigger.h> #include <utils/Log.h> #include "AudioPolicyService.h" diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index 50ee803..5524463 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -190,6 +190,11 @@ public: virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0; virtual void clearAudioPatches(uid_t uid) = 0; + virtual status_t acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device) = 0; + + virtual status_t releaseSoundTriggerSession(audio_session_t session) = 0; }; diff --git a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp index 75745b3..2c51e25 100644 --- a/services/audiopolicy/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/AudioPolicyInterfaceImpl.cpp @@ -531,4 +531,24 @@ status_t AudioPolicyService::setAudioPortConfig(const struct audio_port_config * return mAudioPolicyManager->setAudioPortConfig(config); } +status_t AudioPolicyService::acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device) +{ + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + + return mAudioPolicyManager->acquireSoundTriggerSession(session, ioHandle, device); +} + +status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session) +{ + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + + return mAudioPolicyManager->releaseSoundTriggerSession(session); +} + }; // namespace android diff --git a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp index aa46ace..f20c070 100644 --- a/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp +++ b/services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp @@ -496,10 +496,21 @@ audio_io_handle_t AudioPolicyService::getOutputForAttr(const audio_attributes_t audio_output_flags_t flags, const audio_offload_info_t *offloadInfo) { - //FIXME: temporary to fix build with USE_LEGACY_AUDIO_POLICY - audio_stream_type_t stream = AUDIO_STREAM_MUSIC; + audio_stream_type_t stream = audio_attributes_to_stream_type(attr); + return getOutput(stream, samplingRate, format, channelMask, flags, offloadInfo); } +status_t AudioPolicyService::acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device) +{ + return INVALID_OPERATION; +} + +status_t AudioPolicyService::releaseSoundTriggerSession(audio_session_t session) +{ + return INVALID_OPERATION; +} }; // namespace android diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 65d52d0..aa976b5 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -43,6 +43,7 @@ #include <hardware/audio.h> #include <hardware/audio_effect.h> #include <media/AudioParameter.h> +#include <soundtrigger/SoundTrigger.h> #include "AudioPolicyManager.h" #include "audio_policy_conf.h" @@ -206,9 +207,10 @@ status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address) { - String8 address = String8(device_address); + String8 address = (device_address == NULL) ? String8("") : String8(device_address); - ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address); + ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", + device, state, address.string()); // connect/disconnect only 1 device at a time if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE; @@ -376,9 +378,8 @@ audio_policy_dev_state_t AudioPolicyManager::getDeviceConnectionState(audio_devi const char *device_address) { audio_policy_dev_state_t state = AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE; - String8 address = String8(device_address); sp<DeviceDescriptor> devDesc = new DeviceDescriptor(String8(""), device); - devDesc->mAddress = String8(device_address); + devDesc->mAddress = (device_address == NULL) ? String8("") : String8(device_address); ssize_t index; DeviceVector *deviceVector; @@ -709,7 +710,9 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( config.sample_rate = mTestSamplingRate; config.channel_mask = mTestChannels; config.format = mTestFormat; - config.offload_info = *offloadInfo; + if (offloadInfo != NULL) { + config.offload_info = *offloadInfo; + } status = mpClientInterface->openOutput(0, &mTestOutputs[mCurOutput], &config, @@ -784,7 +787,9 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice( config.sample_rate = samplingRate; config.channel_mask = channelMask; config.format = format; - config.offload_info = *offloadInfo; + if (offloadInfo != NULL) { + config.offload_info = *offloadInfo; + } status = mpClientInterface->openOutput(profile->mModule->mHandle, &output, &config, @@ -1115,6 +1120,17 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, config.channel_mask = channelMask; config.format = format; audio_io_handle_t input = AUDIO_IO_HANDLE_NONE; + + bool isSoundTrigger = false; + if (inputSource == AUDIO_SOURCE_HOTWORD) { + ssize_t index = mSoundTriggerSessions.indexOfKey(session); + if (index >= 0) { + input = mSoundTriggerSessions.valueFor(session); + isSoundTrigger = true; + ALOGV("SoundTrigger capture on session %d input %d", session, input); + } + } + status_t status = mpClientInterface->openInput(profile->mModule->mHandle, &input, &config, @@ -1145,6 +1161,7 @@ audio_io_handle_t AudioPolicyManager::getInput(audio_source_t inputSource, inputDesc->mChannelMask = channelMask; inputDesc->mDevice = device; inputDesc->mSessions.add(session); + inputDesc->mIsSoundTrigger = isSoundTrigger; addInput(input, inputDesc); mpClientInterface->onAudioPortListUpdate(); @@ -1190,6 +1207,9 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, } if (inputDesc->mRefCount == 0) { + if (activeInputsCount() == 0) { + SoundTrigger::setCaptureState(true); + } setInputDevice(input, getNewInputDevice(input), true /* force */); // Automatically enable the remote submix output when input is started. @@ -1238,6 +1258,10 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, } resetInputDevice(input); + + if (activeInputsCount() == 0) { + SoundTrigger::setCaptureState(false); + } } return NO_ERROR; } @@ -2249,6 +2273,31 @@ void AudioPolicyManager::clearAudioPatches(uid_t uid) } } +status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device) +{ + *session = (audio_session_t)mpClientInterface->newAudioUniqueId(); + *ioHandle = (audio_io_handle_t)mpClientInterface->newAudioUniqueId(); + *device = getDeviceForInputSource(AUDIO_SOURCE_HOTWORD); + + mSoundTriggerSessions.add(*session, *ioHandle); + + return NO_ERROR; +} + +status_t AudioPolicyManager::releaseSoundTriggerSession(audio_session_t session) +{ + ssize_t index = mSoundTriggerSessions.indexOfKey(session); + if (index < 0) { + ALOGW("acquireSoundTriggerSession() session %d not registered", session); + return BAD_VALUE; + } + + mSoundTriggerSessions.removeItem(session); + return NO_ERROR; +} + status_t AudioPolicyManager::addAudioPatch(audio_patch_handle_t handle, const sp<AudioPatch>& patch) { @@ -3657,6 +3706,8 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; if (device) break; } + device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_LINE; + if (device) break; device = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_SPEAKER; if (device) break; device = mDefaultOutputDevice->mDeviceType; @@ -3713,6 +3764,9 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; } + if ((device2 == AUDIO_DEVICE_NONE)) { + device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_LINE; + } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDeviceTypes & AUDIO_DEVICE_OUT_WIRED_HEADSET; } @@ -4009,7 +4063,8 @@ status_t AudioPolicyManager::setInputDevice(audio_io_handle_t input, inputDesc->toAudioPortConfig(&patch.sinks[0]); // AUDIO_SOURCE_HOTWORD is for internal use only: // handled as AUDIO_SOURCE_VOICE_RECOGNITION by the audio HAL - if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD) { + if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD && + !inputDesc->mIsSoundTrigger) { patch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_VOICE_RECOGNITION; } patch.num_sinks = 1; @@ -4194,6 +4249,18 @@ audio_io_handle_t AudioPolicyManager::getActiveInput(bool ignoreVirtualInputs) return 0; } +uint32_t AudioPolicyManager::activeInputsCount() const +{ + uint32_t count = 0; + for (size_t i = 0; i < mInputs.size(); i++) { + const sp<AudioInputDescriptor> desc = mInputs.valueAt(i); + if (desc->mRefCount > 0) { + return count++; + } + } + return count; +} + audio_devices_t AudioPolicyManager::getDeviceForVolume(audio_devices_t device) { @@ -4233,10 +4300,13 @@ AudioPolicyManager::device_category AudioPolicyManager::getDeviceCategory(audio_ case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES: return DEVICE_CATEGORY_HEADSET; + case AUDIO_DEVICE_OUT_LINE: + case AUDIO_DEVICE_OUT_AUX_DIGITAL: + /*USB? Remote submix?*/ + return DEVICE_CATEGORY_EXT_MEDIA; case AUDIO_DEVICE_OUT_SPEAKER: case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT: case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER: - case AUDIO_DEVICE_OUT_AUX_DIGITAL: case AUDIO_DEVICE_OUT_USB_ACCESSORY: case AUDIO_DEVICE_OUT_USB_DEVICE: case AUDIO_DEVICE_OUT_REMOTE_SUBMIX: @@ -4303,6 +4373,11 @@ const AudioPolicyManager::VolumeCurvePoint }; const AudioPolicyManager::VolumeCurvePoint + AudioPolicyManager::sExtMediaSystemVolumeCurve[AudioPolicyManager::VOLCNT] = { + {1, -58.0f}, {20, -40.0f}, {60, -21.0f}, {100, -10.0f} +}; + +const AudioPolicyManager::VolumeCurvePoint AudioPolicyManager::sSpeakerMediaVolumeCurve[AudioPolicyManager::VOLCNT] = { {1, -56.0f}, {20, -34.0f}, {60, -11.0f}, {100, 0.0f} }; @@ -4358,52 +4433,62 @@ const AudioPolicyManager::VolumeCurvePoint { // AUDIO_STREAM_VOICE_CALL sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_SYSTEM sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_RING sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_MUSIC sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_ALARM sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_NOTIFICATION sDefaultVolumeCurve, // DEVICE_CATEGORY_HEADSET sSpeakerSonificationVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_BLUETOOTH_SCO sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultVoiceVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_ENFORCED_AUDIBLE sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_DTMF sHeadsetSystemVolumeCurve, // DEVICE_CATEGORY_HEADSET sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultSystemVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultSystemVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sExtMediaSystemVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, { // AUDIO_STREAM_TTS sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_HEADSET sSpeakerMediaVolumeCurve, // DEVICE_CATEGORY_SPEAKER - sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EARPIECE + sDefaultMediaVolumeCurve, // DEVICE_CATEGORY_EARPIECE + sDefaultMediaVolumeCurve // DEVICE_CATEGORY_EXT_MEDIA }, }; @@ -4879,7 +4964,7 @@ status_t AudioPolicyManager::AudioOutputDescriptor::dump(int fd) AudioPolicyManager::AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile) : mId(0), mIoHandle(0), mDevice(AUDIO_DEVICE_NONE), mPatchHandle(0), mRefCount(0), - mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile) + mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false) { if (profile != NULL) { mAudioPort = profile; diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h index e28a362..47235f7 100644 --- a/services/audiopolicy/AudioPolicyManager.h +++ b/services/audiopolicy/AudioPolicyManager.h @@ -172,6 +172,12 @@ public: virtual status_t setAudioPortConfig(const struct audio_port_config *config); virtual void clearAudioPatches(uid_t uid); + virtual status_t acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device); + + virtual status_t releaseSoundTriggerSession(audio_session_t session); + protected: enum routing_strategy { @@ -202,6 +208,7 @@ protected: DEVICE_CATEGORY_HEADSET, DEVICE_CATEGORY_SPEAKER, DEVICE_CATEGORY_EARPIECE, + DEVICE_CATEGORY_EXT_MEDIA, DEVICE_CATEGORY_CNT }; @@ -408,6 +415,8 @@ protected: static const VolumeCurvePoint sDefaultVolumeCurve[AudioPolicyManager::VOLCNT]; // default volume curve for media strategy static const VolumeCurvePoint sDefaultMediaVolumeCurve[AudioPolicyManager::VOLCNT]; + // volume curve for non-media audio on ext media outputs (HDMI, Line, etc) + static const VolumeCurvePoint sExtMediaSystemVolumeCurve[AudioPolicyManager::VOLCNT]; // volume curve for media strategy on speakers static const VolumeCurvePoint sSpeakerMediaVolumeCurve[AudioPolicyManager::VOLCNT]; static const VolumeCurvePoint sSpeakerMediaVolumeCurveDrc[AudioPolicyManager::VOLCNT]; @@ -477,15 +486,18 @@ protected: status_t dump(int fd); - audio_port_handle_t mId; - audio_io_handle_t mIoHandle; // input handle - audio_devices_t mDevice; // current device this input is routed to - audio_patch_handle_t mPatchHandle; - uint32_t mRefCount; // number of AudioRecord clients using this output - uint32_t mOpenRefCount; - audio_source_t mInputSource; // input source selected by application (mediarecorder.h) - const sp<IOProfile> mProfile; // I/O profile this output derives from - SortedVector<audio_session_t> mSessions; // audio sessions attached to this input + audio_port_handle_t mId; + audio_io_handle_t mIoHandle; // input handle + audio_devices_t mDevice; // current device this input is routed to + audio_patch_handle_t mPatchHandle; + uint32_t mRefCount; // number of AudioRecord clients using + // this input + uint32_t mOpenRefCount; + audio_source_t mInputSource; // input source selected by application + //(mediarecorder.h) + const sp<IOProfile> mProfile; // I/O profile this output derives from + SortedVector<audio_session_t> mSessions; // audio sessions attached to this input + bool mIsSoundTrigger; // used by a soundtrigger capture virtual void toAudioPortConfig(struct audio_port_config *dstConfig, const struct audio_port_config *srcConfig = NULL) const; @@ -569,6 +581,8 @@ protected: // ignoreVirtualInputs is true. audio_io_handle_t getActiveInput(bool ignoreVirtualInputs = true); + uint32_t activeInputsCount() const; + // initialize volume curves for each strategy and device category void initializeVolumeCurves(); @@ -769,6 +783,8 @@ protected: DefaultKeyedVector<audio_patch_handle_t, sp<AudioPatch> > mAudioPatches; + DefaultKeyedVector<audio_session_t, audio_io_handle_t> mSoundTriggerSessions; + #ifdef AUDIO_POLICY_TEST Mutex mLock; Condition mWaitWorkCV; diff --git a/services/audiopolicy/AudioPolicyService.h b/services/audiopolicy/AudioPolicyService.h index 97236e3..0044e7a 100644 --- a/services/audiopolicy/AudioPolicyService.h +++ b/services/audiopolicy/AudioPolicyService.h @@ -168,6 +168,12 @@ public: virtual void registerClient(const sp<IAudioPolicyServiceClient>& client); + virtual status_t acquireSoundTriggerSession(audio_session_t *session, + audio_io_handle_t *ioHandle, + audio_devices_t *device); + + virtual status_t releaseSoundTriggerSession(audio_session_t session); + status_t doStopOutput(audio_io_handle_t output, audio_stream_type_t stream, int session = 0); diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk index b7ccaab..572ae56 100644 --- a/services/soundtrigger/Android.mk +++ b/services/soundtrigger/Android.mk @@ -31,10 +31,14 @@ LOCAL_SHARED_LIBRARIES:= \ libbinder \ libcutils \ libhardware \ - libsoundtrigger + libsoundtrigger \ + libmedia -#LOCAL_C_INCLUDES += \ +LOCAL_STATIC_LIBRARIES := \ + libserviceutility +LOCAL_C_INCLUDES += \ + $(TOPDIR)frameworks/av/services/audioflinger LOCAL_MODULE:= libsoundtriggerservice diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp index 747af79..2502e0d 100644 --- a/services/soundtrigger/SoundTriggerHwService.cpp +++ b/services/soundtrigger/SoundTriggerHwService.cpp @@ -22,18 +22,19 @@ #include <sys/types.h> #include <pthread.h> -#include <binder/IServiceManager.h> -#include <binder/MemoryBase.h> -#include <binder/MemoryHeapBase.h> +#include <system/sound_trigger.h> #include <cutils/atomic.h> #include <cutils/properties.h> #include <hardware/hardware.h> +#include <media/AudioSystem.h> #include <utils/Errors.h> #include <utils/Log.h> - -#include "SoundTriggerHwService.h" -#include <system/sound_trigger.h> +#include <binder/IServiceManager.h> +#include <binder/MemoryBase.h> +#include <binder/MemoryHeapBase.h> #include <hardware/sound_trigger.h> +#include <ServiceUtilities.h> +#include "SoundTriggerHwService.h" namespace android { @@ -45,7 +46,9 @@ namespace android { SoundTriggerHwService::SoundTriggerHwService() : BnSoundTriggerHwService(), - mNextUniqueId(1) + mNextUniqueId(1), + mMemoryDealer(new MemoryDealer(1024 * 1024, "SoundTriggerHwService")), + mCaptureState(false) { } @@ -103,6 +106,10 @@ status_t SoundTriggerHwService::listModules(struct sound_trigger_module_descript uint32_t *numModules) { ALOGV("listModules"); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + AutoMutex lock(mServiceLock); if (numModules == NULL || (*numModules != 0 && modules == NULL)) { return BAD_VALUE; @@ -120,6 +127,10 @@ status_t SoundTriggerHwService::attach(const sound_trigger_module_handle_t handl sp<ISoundTrigger>& moduleInterface) { ALOGV("attach module %d", handle); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } + AutoMutex lock(mServiceLock); moduleInterface.clear(); if (client == 0) { @@ -135,15 +146,31 @@ status_t SoundTriggerHwService::attach(const sound_trigger_module_handle_t handl client->asBinder()->linkToDeath(module); moduleInterface = module; + module->setCaptureState_l(mCaptureState); + return NO_ERROR; } -void SoundTriggerHwService::detachModule(sp<Module> module) { +status_t SoundTriggerHwService::setCaptureState(bool active) +{ + ALOGV("setCaptureState %d", active); AutoMutex lock(mServiceLock); + mCaptureState = active; + for (size_t i = 0; i < mModules.size(); i++) { + mModules.valueAt(i)->setCaptureState_l(active); + } + return NO_ERROR; +} + + +void SoundTriggerHwService::detachModule(sp<Module> module) +{ ALOGV("detachModule"); + AutoMutex lock(mServiceLock); module->clearClient(); } + static const int kDumpLockRetries = 50; static const int kDumpLockSleep = 60000; @@ -192,18 +219,175 @@ void SoundTriggerHwService::recognitionCallback(struct sound_trigger_recognition if (module == NULL) { return; } - module->sendRecognitionEvent(event); + sp<SoundTriggerHwService> service = module->service().promote(); + if (service == 0) { + return; + } + + service->sendRecognitionEvent(event, module); } +sp<IMemory> SoundTriggerHwService::prepareRecognitionEvent_l( + struct sound_trigger_recognition_event *event) +{ + sp<IMemory> eventMemory; + + //sanitize event + switch (event->type) { + case SOUND_MODEL_TYPE_KEYPHRASE: + ALOGW_IF(event->data_size != 0 && event->data_offset != + sizeof(struct sound_trigger_phrase_recognition_event), + "prepareRecognitionEvent_l(): invalid data offset %u for keyphrase event type", + event->data_offset); + event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event); + break; + case SOUND_MODEL_TYPE_UNKNOWN: + ALOGW_IF(event->data_size != 0 && event->data_offset != + sizeof(struct sound_trigger_recognition_event), + "prepareRecognitionEvent_l(): invalid data offset %u for unknown event type", + event->data_offset); + event->data_offset = sizeof(struct sound_trigger_recognition_event); + break; + default: + return eventMemory; + } + + size_t size = event->data_offset + event->data_size; + eventMemory = mMemoryDealer->allocate(size); + if (eventMemory == 0 || eventMemory->pointer() == NULL) { + eventMemory.clear(); + return eventMemory; + } + memcpy(eventMemory->pointer(), event, size); + + return eventMemory; +} + +void SoundTriggerHwService::sendRecognitionEvent(struct sound_trigger_recognition_event *event, + Module *module) + { + AutoMutex lock(mServiceLock); + if (module == NULL) { + return; + } + sp<IMemory> eventMemory = prepareRecognitionEvent_l(event); + if (eventMemory == 0) { + return; + } + sp<Module> strongModule; + for (size_t i = 0; i < mModules.size(); i++) { + if (mModules.valueAt(i).get() == module) { + strongModule = mModules.valueAt(i); + break; + } + } + if (strongModule == 0) { + return; + } + + sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, + eventMemory, strongModule)); +} -void SoundTriggerHwService::sendRecognitionEvent(const sp<RecognitionEvent>& event) +// static +void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event, + void *cookie) { - mCallbackThread->sendRecognitionEvent(event); + Module *module = (Module *)cookie; + if (module == NULL) { + return; + } + sp<SoundTriggerHwService> service = module->service().promote(); + if (service == 0) { + return; + } + + service->sendSoundModelEvent(event, module); } -void SoundTriggerHwService::onRecognitionEvent(const sp<RecognitionEvent>& event) +sp<IMemory> SoundTriggerHwService::prepareSoundModelEvent_l(struct sound_trigger_model_event *event) { - ALOGV("onRecognitionEvent"); + sp<IMemory> eventMemory; + + size_t size = event->data_offset + event->data_size; + eventMemory = mMemoryDealer->allocate(size); + if (eventMemory == 0 || eventMemory->pointer() == NULL) { + eventMemory.clear(); + return eventMemory; + } + memcpy(eventMemory->pointer(), event, size); + + return eventMemory; +} + +void SoundTriggerHwService::sendSoundModelEvent(struct sound_trigger_model_event *event, + Module *module) +{ + AutoMutex lock(mServiceLock); + sp<IMemory> eventMemory = prepareSoundModelEvent_l(event); + if (eventMemory == 0) { + return; + } + sp<Module> strongModule; + for (size_t i = 0; i < mModules.size(); i++) { + if (mModules.valueAt(i).get() == module) { + strongModule = mModules.valueAt(i); + break; + } + } + if (strongModule == 0) { + return; + } + sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SOUNDMODEL, + eventMemory, strongModule)); +} + + +sp<IMemory> SoundTriggerHwService::prepareServiceStateEvent_l(sound_trigger_service_state_t state) +{ + sp<IMemory> eventMemory; + + size_t size = sizeof(sound_trigger_service_state_t); + eventMemory = mMemoryDealer->allocate(size); + if (eventMemory == 0 || eventMemory->pointer() == NULL) { + eventMemory.clear(); + return eventMemory; + } + *((sound_trigger_service_state_t *)eventMemory->pointer()) = state; + return eventMemory; +} + +// call with mServiceLock held +void SoundTriggerHwService::sendServiceStateEvent_l(sound_trigger_service_state_t state, + Module *module) +{ + sp<IMemory> eventMemory = prepareServiceStateEvent_l(state); + if (eventMemory == 0) { + return; + } + sp<Module> strongModule; + for (size_t i = 0; i < mModules.size(); i++) { + if (mModules.valueAt(i).get() == module) { + strongModule = mModules.valueAt(i); + break; + } + } + if (strongModule == 0) { + return; + } + sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_SERVICE_STATE, + eventMemory, strongModule)); +} + +// call with mServiceLock held +void SoundTriggerHwService::sendCallbackEvent_l(const sp<CallbackEvent>& event) +{ + mCallbackThread->sendCallbackEvent(event); +} + +void SoundTriggerHwService::onCallbackEvent(const sp<CallbackEvent>& event) +{ + ALOGV("onCallbackEvent"); sp<Module> module; { AutoMutex lock(mServiceLock); @@ -212,15 +396,12 @@ void SoundTriggerHwService::onRecognitionEvent(const sp<RecognitionEvent>& event return; } } - module->onRecognitionEvent(event->mEventMemory); -} - -// static -void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event __unused, - void *cookie) -{ - Module *module = (Module *)cookie; - + module->onCallbackEvent(event); + { + AutoMutex lock(mServiceLock); + // clear now to execute with mServiceLock locked + event->mMemory.clear(); + } } #undef LOG_TAG @@ -233,7 +414,10 @@ SoundTriggerHwService::CallbackThread::CallbackThread(const wp<SoundTriggerHwSer SoundTriggerHwService::CallbackThread::~CallbackThread() { - mEventQueue.clear(); + while (!mEventQueue.isEmpty()) { + mEventQueue[0]->mMemory.clear(); + mEventQueue.removeAt(0); + } } void SoundTriggerHwService::CallbackThread::onFirstRef() @@ -244,7 +428,7 @@ void SoundTriggerHwService::CallbackThread::onFirstRef() bool SoundTriggerHwService::CallbackThread::threadLoop() { while (!exitPending()) { - sp<RecognitionEvent> event; + sp<CallbackEvent> event; sp<SoundTriggerHwService> service; { Mutex::Autolock _l(mCallbackLock); @@ -261,7 +445,7 @@ bool SoundTriggerHwService::CallbackThread::threadLoop() service = mService.promote(); } if (service != 0) { - service->onRecognitionEvent(event); + service->onCallbackEvent(event); } } return false; @@ -274,25 +458,25 @@ void SoundTriggerHwService::CallbackThread::exit() mCallbackCond.broadcast(); } -void SoundTriggerHwService::CallbackThread::sendRecognitionEvent( - const sp<SoundTriggerHwService::RecognitionEvent>& event) +void SoundTriggerHwService::CallbackThread::sendCallbackEvent( + const sp<SoundTriggerHwService::CallbackEvent>& event) { AutoMutex lock(mCallbackLock); mEventQueue.add(event); mCallbackCond.signal(); } -SoundTriggerHwService::RecognitionEvent::RecognitionEvent( - sp<IMemory> eventMemory, - wp<Module> module) - : mEventMemory(eventMemory), mModule(module) +SoundTriggerHwService::CallbackEvent::CallbackEvent(event_type type, sp<IMemory> memory, + wp<Module> module) + : mType(type), mMemory(memory), mModule(module) { } -SoundTriggerHwService::RecognitionEvent::~RecognitionEvent() +SoundTriggerHwService::CallbackEvent::~CallbackEvent() { } + #undef LOG_TAG #define LOG_TAG "SoundTriggerHwService::Module" @@ -301,7 +485,7 @@ SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service, sound_trigger_module_descriptor descriptor, const sp<ISoundTriggerClient>& client) : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor), - mClient(client) + mClient(client), mServiceState(SOUND_TRIGGER_STATE_NO_INIT) { } @@ -310,6 +494,9 @@ SoundTriggerHwService::Module::~Module() { void SoundTriggerHwService::Module::detach() { ALOGV("detach()"); + if (!captureHotwordAllowed()) { + return; + } { AutoMutex lock(mLock); for (size_t i = 0; i < mModels.size(); i++) { @@ -317,7 +504,6 @@ void SoundTriggerHwService::Module::detach() { ALOGV("detach() unloading model %d", model->mHandle); if (model->mState == Model::STATE_ACTIVE) { mHwDevice->stop_recognition(mHwDevice, model->mHandle); - model->deallocateMemory(); } mHwDevice->unload_sound_model(mHwDevice, model->mHandle); } @@ -337,6 +523,9 @@ status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelM 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()"); @@ -351,16 +540,30 @@ status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelM SoundTriggerHwService::soundModelCallback, this, handle); - if (status == NO_ERROR) { - mModels.replaceValueFor(*handle, new Model(*handle)); + if (status != NO_ERROR) { + return status; + } + audio_session_t session; + audio_io_handle_t ioHandle; + audio_devices_t device; + + status = AudioSystem::acquireSoundTriggerSession(&session, &ioHandle, &device); + if (status != NO_ERROR) { + return status; } + sp<Model> model = new Model(*handle, session, ioHandle, device, sound_model->type); + mModels.replaceValueFor(*handle, model); + return status; } status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle) { ALOGV("unloadSoundModel() model handle %d", handle); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } AutoMutex lock(mLock); ssize_t index = mModels.indexOfKey(handle); @@ -371,8 +574,8 @@ status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t ha mModels.removeItem(handle); if (model->mState == Model::STATE_ACTIVE) { mHwDevice->stop_recognition(mHwDevice, model->mHandle); - model->deallocateMemory(); } + AudioSystem::releaseSoundTriggerSession(model->mCaptureSession); return mHwDevice->unload_sound_model(mHwDevice, handle); } @@ -380,6 +583,9 @@ status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t ha const sp<IMemory>& dataMemory) { ALOGV("startRecognition() model handle %d", handle); + if (!captureHotwordAllowed()) { + return PERMISSION_DENIED; + } if (dataMemory != 0 && dataMemory->pointer() == NULL) { ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()"); @@ -387,6 +593,9 @@ status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t ha } AutoMutex lock(mLock); + if (mServiceState == SOUND_TRIGGER_STATE_DISABLED) { + return INVALID_OPERATION; + } sp<Model> model = getModel(handle); if (model == 0) { return BAD_VALUE; @@ -399,22 +608,31 @@ status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t ha if (model->mState == Model::STATE_ACTIVE) { return INVALID_OPERATION; } - model->mState = Model::STATE_ACTIVE; struct sound_trigger_recognition_config *config = (struct sound_trigger_recognition_config *)dataMemory->pointer(); //TODO: get capture handle and device from audio policy service - config->capture_handle = AUDIO_IO_HANDLE_NONE; - config->capture_device = AUDIO_DEVICE_NONE; - return mHwDevice->start_recognition(mHwDevice, handle, config, + config->capture_handle = model->mCaptureIOHandle; + config->capture_device = model->mCaptureDevice; + status_t status = mHwDevice->start_recognition(mHwDevice, handle, config, SoundTriggerHwService::recognitionCallback, this); + + if (status == NO_ERROR) { + model->mState = Model::STATE_ACTIVE; + model->mConfig = *config; + } + + return status; } 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> model = getModel(handle); @@ -426,93 +644,62 @@ status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t han return INVALID_OPERATION; } mHwDevice->stop_recognition(mHwDevice, handle); - model->deallocateMemory(); model->mState = Model::STATE_IDLE; return NO_ERROR; } -void SoundTriggerHwService::Module::sendRecognitionEvent( - struct sound_trigger_recognition_event *event) -{ - sp<SoundTriggerHwService> service; - sp<IMemory> eventMemory; - ALOGV("sendRecognitionEvent for model %d", event->model); - { - AutoMutex lock(mLock); - sp<Model> model = getModel(event->model); - if (model == 0) { - return; - } - if (model->mState != Model::STATE_ACTIVE) { - ALOGV("sendRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState); - return; - } - if (mClient == 0) { - return; - } - service = mService.promote(); - if (service == 0) { - return; - } - - //sanitize event - switch (event->type) { - case SOUND_MODEL_TYPE_KEYPHRASE: - ALOGW_IF(event->data_offset != - sizeof(struct sound_trigger_phrase_recognition_event), - "sendRecognitionEvent(): invalid data offset %u for keyphrase event type", - event->data_offset); - event->data_offset = sizeof(struct sound_trigger_phrase_recognition_event); - break; - case SOUND_MODEL_TYPE_UNKNOWN: - ALOGW_IF(event->data_offset != - sizeof(struct sound_trigger_recognition_event), - "sendRecognitionEvent(): invalid data offset %u for unknown event type", - event->data_offset); - event->data_offset = sizeof(struct sound_trigger_recognition_event); - break; - default: - return; - } - - size_t size = event->data_offset + event->data_size; - eventMemory = model->allocateMemory(size); - if (eventMemory == 0 || eventMemory->pointer() == NULL) { - return; - } - memcpy(eventMemory->pointer(), event, size); - } - service->sendRecognitionEvent(new RecognitionEvent(eventMemory, this)); -} -void SoundTriggerHwService::Module::onRecognitionEvent(sp<IMemory> eventMemory) +void SoundTriggerHwService::Module::onCallbackEvent(const sp<CallbackEvent>& event) { - ALOGV("Module::onRecognitionEvent"); + ALOGV("onCallbackEvent type %d", event->mType); AutoMutex lock(mLock); + sp<IMemory> eventMemory = event->mMemory; if (eventMemory == 0 || eventMemory->pointer() == NULL) { return; } - struct sound_trigger_recognition_event *event = - (struct sound_trigger_recognition_event *)eventMemory->pointer(); - - sp<Model> model = getModel(event->model); - if (model == 0) { - ALOGI("%s model == 0", __func__); - return; - } - if (model->mState != Model::STATE_ACTIVE) { - ALOGV("onRecognitionEvent model->mState %d != Model::STATE_ACTIVE", model->mState); - return; - } if (mClient == 0) { ALOGI("%s mClient == 0", __func__); return; } - mClient->onRecognitionEvent(eventMemory); - model->mState = Model::STATE_IDLE; - model->deallocateMemory(); + + switch (event->mType) { + case CallbackEvent::TYPE_RECOGNITION: { + struct sound_trigger_recognition_event *recognitionEvent = + (struct sound_trigger_recognition_event *)eventMemory->pointer(); + + sp<Model> model = getModel(recognitionEvent->model); + if (model == 0) { + ALOGW("%s model == 0", __func__); + return; + } + if (model->mState != Model::STATE_ACTIVE) { + ALOGV("onCallbackEvent model->mState %d != Model::STATE_ACTIVE", model->mState); + return; + } + + recognitionEvent->capture_session = model->mCaptureSession; + mClient->onRecognitionEvent(eventMemory); + model->mState = Model::STATE_IDLE; + } break; + case CallbackEvent::TYPE_SOUNDMODEL: { + struct sound_trigger_model_event *soundmodelEvent = + (struct sound_trigger_model_event *)eventMemory->pointer(); + + sp<Model> model = getModel(soundmodelEvent->model); + if (model == 0) { + ALOGW("%s model == 0", __func__); + return; + } + mClient->onSoundModelEvent(eventMemory); + } break; + case CallbackEvent::TYPE_SERVICE_STATE: { + mClient->onServiceStateChange(eventMemory); + } break; + default: + LOG_ALWAYS_FATAL("onCallbackEvent unknown event type %d", event->mType); + } } sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel( @@ -532,30 +719,80 @@ void SoundTriggerHwService::Module::binderDied( detach(); } - -SoundTriggerHwService::Model::Model(sound_model_handle_t handle) : - mHandle(handle), mState(STATE_IDLE), mInputHandle(AUDIO_IO_HANDLE_NONE), - mCaptureSession(AUDIO_SESSION_ALLOCATE), - mMemoryDealer(new MemoryDealer(sizeof(struct sound_trigger_recognition_event), - "SoundTriggerHwService::Event")) +// Called with mServiceLock held +void SoundTriggerHwService::Module::setCaptureState_l(bool active) { + ALOGV("Module::setCaptureState_l %d", active); + sp<SoundTriggerHwService> service; + sound_trigger_service_state_t state; -} + Vector< sp<IMemory> > events; + { + AutoMutex lock(mLock); + state = (active && !mDescriptor.properties.concurrent_capture) ? + SOUND_TRIGGER_STATE_DISABLED : SOUND_TRIGGER_STATE_ENABLED; + + if (state == mServiceState) { + return; + } + mServiceState = state; -sp<IMemory> SoundTriggerHwService::Model::allocateMemory(size_t size) -{ - sp<IMemory> memory; - if (mMemoryDealer->getMemoryHeap()->getSize() < size) { - mMemoryDealer = new MemoryDealer(size, "SoundTriggerHwService::Event"); + service = mService.promote(); + if (service == 0) { + return; + } + + if (state == SOUND_TRIGGER_STATE_ENABLED) { + goto exit; + } + + for (size_t i = 0; i < mModels.size(); i++) { + sp<Model> model = mModels.valueAt(i); + if (model->mState == Model::STATE_ACTIVE) { + mHwDevice->stop_recognition(mHwDevice, model->mHandle); + // keep model in ACTIVE state so that event is processed by onCallbackEvent() + struct sound_trigger_phrase_recognition_event phraseEvent; + switch (model->mType) { + case SOUND_MODEL_TYPE_KEYPHRASE: + phraseEvent.num_phrases = model->mConfig.num_phrases; + for (size_t i = 0; i < phraseEvent.num_phrases; i++) { + phraseEvent.phrase_extras[i] = model->mConfig.phrases[i]; + } + break; + case SOUND_MODEL_TYPE_UNKNOWN: + default: + break; + } + phraseEvent.common.status = RECOGNITION_STATUS_ABORT; + phraseEvent.common.type = model->mType; + phraseEvent.common.model = model->mHandle; + phraseEvent.common.data_size = 0; + sp<IMemory> eventMemory = service->prepareRecognitionEvent_l(&phraseEvent.common); + if (eventMemory != 0) { + events.add(eventMemory); + } + } + } + } + + for (size_t i = 0; i < events.size(); i++) { + service->sendCallbackEvent_l(new CallbackEvent(CallbackEvent::TYPE_RECOGNITION, events[i], + this)); } - memory = mMemoryDealer->allocate(size); - return memory; + +exit: + service->sendServiceStateEvent_l(state, this); } -void SoundTriggerHwService::Model::deallocateMemory() + +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) : + mHandle(handle), mState(STATE_IDLE), mCaptureSession(session), + mCaptureIOHandle(ioHandle), mCaptureDevice(device), mType(type) { - mMemoryDealer->deallocate(0); + } status_t SoundTriggerHwService::Module::dump(int fd __unused, diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h index 377f2a1..d05dacd 100644 --- a/services/soundtrigger/SoundTriggerHwService.h +++ b/services/soundtrigger/SoundTriggerHwService.h @@ -53,6 +53,8 @@ public: const sp<ISoundTriggerClient>& client, sp<ISoundTrigger>& module); + virtual status_t setCaptureState(bool active); + virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); @@ -66,17 +68,33 @@ public: STATE_ACTIVE }; - Model(sound_model_handle_t handle); + 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); ~Model() {} - sp<IMemory> allocateMemory(size_t size); - void deallocateMemory(); - sound_model_handle_t mHandle; int mState; - audio_io_handle_t mInputHandle; audio_session_t mCaptureSession; - sp<MemoryDealer> mMemoryDealer; + audio_io_handle_t mCaptureIOHandle; + audio_devices_t mCaptureDevice; + sound_trigger_sound_model_type_t mType; + struct sound_trigger_recognition_config mConfig; + }; + + class CallbackEvent : public RefBase { + public: + typedef enum { + TYPE_RECOGNITION, + TYPE_SOUNDMODEL, + TYPE_SERVICE_STATE, + } event_type; + CallbackEvent(event_type type, sp<IMemory> memory, wp<Module> module); + + virtual ~CallbackEvent(); + + event_type mType; + sp<IMemory> mMemory; + wp<Module> mModule; }; class Module : public virtual RefBase, @@ -109,36 +127,29 @@ public: struct sound_trigger_module_descriptor descriptor() { return mDescriptor; } void setClient(sp<ISoundTriggerClient> client) { mClient = client; } void clearClient() { mClient.clear(); } - sp<ISoundTriggerClient> client() { return mClient; } + sp<ISoundTriggerClient> client() const { return mClient; } + wp<SoundTriggerHwService> service() const { return mService; } - void sendRecognitionEvent(struct sound_trigger_recognition_event *event); - void onRecognitionEvent(sp<IMemory> eventMemory); + void onCallbackEvent(const sp<CallbackEvent>& event); sp<Model> getModel(sound_model_handle_t handle); + void setCaptureState_l(bool active); + // IBinder::DeathRecipient implementation virtual void binderDied(const wp<IBinder> &who); private: + Mutex mLock; wp<SoundTriggerHwService> mService; struct sound_trigger_hw_device* mHwDevice; struct sound_trigger_module_descriptor mDescriptor; sp<ISoundTriggerClient> mClient; DefaultKeyedVector< sound_model_handle_t, sp<Model> > mModels; + sound_trigger_service_state_t mServiceState; }; // class Module - class RecognitionEvent : public RefBase { - public: - - RecognitionEvent(sp<IMemory> eventMemory, wp<Module> module); - - virtual ~RecognitionEvent(); - - sp<IMemory> mEventMemory; - wp<Module> mModule; - }; - class CallbackThread : public Thread { public: @@ -153,22 +164,30 @@ public: virtual void onFirstRef(); void exit(); - void sendRecognitionEvent(const sp<RecognitionEvent>& event); + void sendCallbackEvent(const sp<CallbackEvent>& event); private: wp<SoundTriggerHwService> mService; Condition mCallbackCond; Mutex mCallbackLock; - Vector< sp<RecognitionEvent> > mEventQueue; + Vector< sp<CallbackEvent> > mEventQueue; }; - void detachModule(sp<Module> module); + void detachModule(sp<Module> module); static void recognitionCallback(struct sound_trigger_recognition_event *event, void *cookie); - void sendRecognitionEvent(const sp<RecognitionEvent>& event); - void onRecognitionEvent(const sp<RecognitionEvent>& event); + sp<IMemory> prepareRecognitionEvent_l(struct sound_trigger_recognition_event *event); + void sendRecognitionEvent(struct sound_trigger_recognition_event *event, Module *module); static void soundModelCallback(struct sound_trigger_model_event *event, void *cookie); + sp<IMemory> prepareSoundModelEvent_l(struct sound_trigger_model_event *event); + void sendSoundModelEvent(struct sound_trigger_model_event *event, Module *module); + + sp<IMemory> prepareServiceStateEvent_l(sound_trigger_service_state_t state); + void sendServiceStateEvent_l(sound_trigger_service_state_t state, Module *module); + + void sendCallbackEvent_l(const sp<CallbackEvent>& event); + void onCallbackEvent(const sp<CallbackEvent>& event); private: @@ -178,6 +197,8 @@ private: volatile int32_t mNextUniqueId; DefaultKeyedVector< sound_trigger_module_handle_t, sp<Module> > mModules; sp<CallbackThread> mCallbackThread; + sp<MemoryDealer> mMemoryDealer; + bool mCaptureState; }; } // namespace android diff --git a/soundtrigger/ISoundTriggerClient.cpp b/soundtrigger/ISoundTriggerClient.cpp index 1d0c0ec..b0b4428 100644 --- a/soundtrigger/ISoundTriggerClient.cpp +++ b/soundtrigger/ISoundTriggerClient.cpp @@ -27,6 +27,8 @@ namespace android { enum { ON_RECOGNITION_EVENT = IBinder::FIRST_CALL_TRANSACTION, + ON_SOUNDMODEL_EVENT, + ON_SERVICE_STATE_CHANGE }; class BpSoundTriggerClient: public BpInterface<ISoundTriggerClient> @@ -47,6 +49,25 @@ public: data, &reply); } + + virtual void onSoundModelEvent(const sp<IMemory>& eventMemory) + { + Parcel data, reply; + data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor()); + data.writeStrongBinder(eventMemory->asBinder()); + remote()->transact(ON_SOUNDMODEL_EVENT, + data, + &reply); + } + virtual void onServiceStateChange(const sp<IMemory>& eventMemory) + { + Parcel data, reply; + data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor()); + data.writeStrongBinder(eventMemory->asBinder()); + remote()->transact(ON_SERVICE_STATE_CHANGE, + data, + &reply); + } }; IMPLEMENT_META_INTERFACE(SoundTriggerClient, @@ -65,6 +86,20 @@ status_t BnSoundTriggerClient::onTransact( onRecognitionEvent(eventMemory); return NO_ERROR; } break; + case ON_SOUNDMODEL_EVENT: { + CHECK_INTERFACE(ISoundTriggerClient, data, reply); + sp<IMemory> eventMemory = interface_cast<IMemory>( + data.readStrongBinder()); + onSoundModelEvent(eventMemory); + return NO_ERROR; + } break; + case ON_SERVICE_STATE_CHANGE: { + CHECK_INTERFACE(ISoundTriggerClient, data, reply); + sp<IMemory> eventMemory = interface_cast<IMemory>( + data.readStrongBinder()); + onServiceStateChange(eventMemory); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/soundtrigger/ISoundTriggerHwService.cpp b/soundtrigger/ISoundTriggerHwService.cpp index c9a0c24..05728e9 100644 --- a/soundtrigger/ISoundTriggerHwService.cpp +++ b/soundtrigger/ISoundTriggerHwService.cpp @@ -37,6 +37,7 @@ namespace android { enum { LIST_MODULES = IBinder::FIRST_CALL_TRANSACTION, ATTACH, + SET_CAPTURE_STATE, }; class BpSoundTriggerHwService: public BpInterface<ISoundTriggerHwService> @@ -90,6 +91,18 @@ public: return status; } + virtual status_t setCaptureState(bool active) + { + Parcel data, reply; + data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor()); + data.writeInt32(active); + status_t status = remote()->transact(SET_CAPTURE_STATE, data, &reply); + if (status == NO_ERROR) { + status = reply.readInt32(); + } + return status; + } + }; IMPLEMENT_META_INTERFACE(SoundTriggerHwService, "android.hardware.ISoundTriggerHwService"); @@ -140,6 +153,13 @@ status_t BnSoundTriggerHwService::onTransact( } return NO_ERROR; } break; + + case SET_CAPTURE_STATE: { + CHECK_INTERFACE(ISoundTriggerHwService, data, reply); + reply->writeInt32(setCaptureState((bool)data.readInt32())); + return NO_ERROR; + } break; + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp index e43acd0..0015c30 100644 --- a/soundtrigger/SoundTrigger.cpp +++ b/soundtrigger/SoundTrigger.cpp @@ -113,6 +113,16 @@ sp<SoundTrigger> SoundTrigger::attach(const sound_trigger_module_handle_t module } +status_t SoundTrigger::setCaptureState(bool active) +{ + ALOGV("setCaptureState(%d)", active); + const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService(); + if (service == 0) { + return NO_INIT; + } + return service->setCaptureState(active); +} + // SoundTrigger SoundTrigger::SoundTrigger(sound_trigger_module_handle_t module, const sp<SoundTriggerCallback>& callback) @@ -192,6 +202,31 @@ void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory) } } +void SoundTrigger::onSoundModelEvent(const sp<IMemory>& eventMemory) +{ + Mutex::Autolock _l(mLock); + if (eventMemory == 0 || eventMemory->pointer() == NULL) { + return; + } + + if (mCallback != 0) { + mCallback->onSoundModelEvent( + (struct sound_trigger_model_event *)eventMemory->pointer()); + } +} + +void SoundTrigger::onServiceStateChange(const sp<IMemory>& eventMemory) +{ + Mutex::Autolock _l(mLock); + if (eventMemory == 0 || eventMemory->pointer() == NULL) { + return; + } + + if (mCallback != 0) { + mCallback->onServiceStateChange( + *((sound_trigger_service_state_t *)eventMemory->pointer())); + } +} //IBinder::DeathRecipient void SoundTrigger::binderDied(const wp<IBinder>& who __unused) { |