diff options
| -rw-r--r-- | include/soundtrigger/ISoundTrigger.h | 59 | ||||
| -rw-r--r-- | include/soundtrigger/ISoundTriggerClient.h | 49 | ||||
| -rw-r--r-- | include/soundtrigger/ISoundTriggerHwService.h | 57 | ||||
| -rw-r--r-- | include/soundtrigger/SoundTrigger.h | 75 | ||||
| -rw-r--r-- | include/soundtrigger/SoundTriggerCallback.h | 40 | ||||
| -rw-r--r-- | media/mediaserver/Android.mk | 6 | ||||
| -rw-r--r-- | media/mediaserver/main_mediaserver.cpp | 2 | ||||
| -rw-r--r-- | services/soundtrigger/Android.mk | 41 | ||||
| -rw-r--r-- | services/soundtrigger/SoundTriggerHwService.cpp | 566 | ||||
| -rw-r--r-- | services/soundtrigger/SoundTriggerHwService.h | 185 | ||||
| -rw-r--r-- | soundtrigger/Android.mk | 38 | ||||
| -rw-r--r-- | soundtrigger/ISoundTrigger.cpp | 177 | ||||
| -rw-r--r-- | soundtrigger/ISoundTriggerClient.cpp | 75 | ||||
| -rw-r--r-- | soundtrigger/ISoundTriggerHwService.cpp | 150 | ||||
| -rw-r--r-- | soundtrigger/SoundTrigger.cpp | 253 | 
15 files changed, 1771 insertions, 2 deletions
diff --git a/include/soundtrigger/ISoundTrigger.h b/include/soundtrigger/ISoundTrigger.h new file mode 100644 index 0000000..5fd8eb2 --- /dev/null +++ b/include/soundtrigger/ISoundTrigger.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_ISOUNDTRIGGER_H +#define ANDROID_HARDWARE_ISOUNDTRIGGER_H + +#include <utils/RefBase.h> +#include <binder/IInterface.h> +#include <binder/Parcel.h> +#include <binder/IMemory.h> +#include <system/sound_trigger.h> + +namespace android { + +class ISoundTrigger : public IInterface +{ +public: +    DECLARE_META_INTERFACE(SoundTrigger); + +    virtual void detach() = 0; + +    virtual status_t loadSoundModel(const sp<IMemory>& modelMemory, +                                    sound_model_handle_t *handle) = 0; + +    virtual status_t unloadSoundModel(sound_model_handle_t handle) = 0; + +    virtual status_t startRecognition(sound_model_handle_t handle, +                                      const sp<IMemory>& dataMemory) = 0; +    virtual status_t stopRecognition(sound_model_handle_t handle) = 0; + +}; + +// ---------------------------------------------------------------------------- + +class BnSoundTrigger: public BnInterface<ISoundTrigger> +{ +public: +    virtual status_t    onTransact( uint32_t code, +                                    const Parcel& data, +                                    Parcel* reply, +                                    uint32_t flags = 0); +}; + +}; // namespace android + +#endif //ANDROID_HARDWARE_ISOUNDTRIGGER_H diff --git a/include/soundtrigger/ISoundTriggerClient.h b/include/soundtrigger/ISoundTriggerClient.h new file mode 100644 index 0000000..7f86d02 --- /dev/null +++ b/include/soundtrigger/ISoundTriggerClient.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_ISOUNDTRIGGER_CLIENT_H +#define ANDROID_HARDWARE_ISOUNDTRIGGER_CLIENT_H + +#include <utils/RefBase.h> +#include <binder/IInterface.h> +#include <binder/Parcel.h> + +namespace android { + +class ISoundTriggerClient : public IInterface +{ +public: + +    DECLARE_META_INTERFACE(SoundTriggerClient); + +    virtual void onRecognitionEvent(const sp<IMemory>& eventMemory) = 0; + +}; + +// ---------------------------------------------------------------------------- + +class BnSoundTriggerClient : public BnInterface<ISoundTriggerClient> +{ +public: +    virtual status_t    onTransact( uint32_t code, +                                    const Parcel& data, +                                    Parcel* reply, +                                    uint32_t flags = 0); +}; + +}; // namespace android + +#endif //ANDROID_HARDWARE_ISOUNDTRIGGER_CLIENT_H diff --git a/include/soundtrigger/ISoundTriggerHwService.h b/include/soundtrigger/ISoundTriggerHwService.h new file mode 100644 index 0000000..05a764a --- /dev/null +++ b/include/soundtrigger/ISoundTriggerHwService.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_ISOUNDTRIGGER_SERVICE_H +#define ANDROID_HARDWARE_ISOUNDTRIGGER_SERVICE_H + +#include <utils/RefBase.h> +#include <binder/IInterface.h> +#include <binder/Parcel.h> +#include <system/sound_trigger.h> + +namespace android { + +class ISoundTrigger; +class ISoundTriggerClient; + +class ISoundTriggerHwService : public IInterface +{ +public: + +    DECLARE_META_INTERFACE(SoundTriggerHwService); + +    virtual status_t listModules(struct sound_trigger_module_descriptor *modules, +                                 uint32_t *numModules) = 0; + +    virtual status_t attach(const sound_trigger_module_handle_t handle, +                                      const sp<ISoundTriggerClient>& client, +                                      sp<ISoundTrigger>& module) = 0; +}; + +// ---------------------------------------------------------------------------- + +class BnSoundTriggerHwService: public BnInterface<ISoundTriggerHwService> +{ +public: +    virtual status_t    onTransact( uint32_t code, +                                    const Parcel& data, +                                    Parcel* reply, +                                    uint32_t flags = 0); +}; + +}; // namespace android + +#endif //ANDROID_HARDWARE_ISOUNDTRIGGER_SERVICE_H diff --git a/include/soundtrigger/SoundTrigger.h b/include/soundtrigger/SoundTrigger.h new file mode 100644 index 0000000..1f7f286 --- /dev/null +++ b/include/soundtrigger/SoundTrigger.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_H +#define ANDROID_HARDWARE_SOUNDTRIGGER_H + +#include <binder/IBinder.h> +#include <soundtrigger/SoundTriggerCallback.h> +#include <soundtrigger/ISoundTrigger.h> +#include <soundtrigger/ISoundTriggerHwService.h> +#include <soundtrigger/ISoundTriggerClient.h> +#include <system/sound_trigger.h> + +namespace android { + +class MemoryDealer; + +class SoundTrigger : public BnSoundTriggerClient, +                        public IBinder::DeathRecipient +{ +public: +    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(); + +            void detach(); + +            status_t loadSoundModel(const sp<IMemory>& modelMemory, +                                            sound_model_handle_t *handle); + +            status_t unloadSoundModel(sound_model_handle_t handle); + +            status_t startRecognition(sound_model_handle_t handle, const sp<IMemory>& dataMemory); +            status_t stopRecognition(sound_model_handle_t handle); + +            // BpSoundTriggerClient +            virtual void onRecognitionEvent(const sp<IMemory>& eventMemory); + +            //IBinder::DeathRecipient +            virtual void binderDied(const wp<IBinder>& who); + +            static status_t stringToGuid(const char *str, sound_trigger_uuid_t *guid); +            static status_t guidToString(const sound_trigger_uuid_t *guid, +                                         char *str, size_t maxLen); + +private: +            SoundTrigger(sound_trigger_module_handle_t module, +                            const sp<SoundTriggerCallback>&); +            static const sp<ISoundTriggerHwService>& getSoundTriggerHwService(); + +            Mutex                               mLock; +            sp<ISoundTrigger>                   mISoundTrigger; +            const sound_trigger_module_handle_t mModule; +            sp<SoundTriggerCallback>            mCallback; +}; + +}; // namespace android + +#endif //ANDROID_HARDWARE_SOUNDTRIGGER_H diff --git a/include/soundtrigger/SoundTriggerCallback.h b/include/soundtrigger/SoundTriggerCallback.h new file mode 100644 index 0000000..8a5ba02 --- /dev/null +++ b/include/soundtrigger/SoundTriggerCallback.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_CALLBACK_H +#define ANDROID_HARDWARE_SOUNDTRIGGER_CALLBACK_H + +#include <utils/RefBase.h> +#include <system/sound_trigger.h> + +namespace android { + +class SoundTriggerCallback : public RefBase +{ +public: + +            SoundTriggerCallback() {} +    virtual ~SoundTriggerCallback() {} + +    virtual void onRecognitionEvent(struct sound_trigger_recognition_event *event) = 0; + +    virtual void onServiceDied() = 0; + +}; + +}; // namespace android + +#endif //ANDROID_HARDWARE_SOUNDTRIGGER_CALLBACK_H diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk index 786bf0d..3a280f0 100644 --- a/media/mediaserver/Android.mk +++ b/media/mediaserver/Android.mk @@ -25,7 +25,8 @@ LOCAL_SHARED_LIBRARIES := \  	libmediaplayerservice \  	libutils \  	liblog \ -	libbinder +	libbinder \ +	libsoundtriggerservice  LOCAL_STATIC_LIBRARIES := \  	libregistermsext @@ -36,7 +37,8 @@ LOCAL_C_INCLUDES := \      frameworks/av/services/audioflinger \      frameworks/av/services/audiopolicy \      frameworks/av/services/camera/libcameraservice \ -    $(call include-path-for, audio-utils) +    $(call include-path-for, audio-utils) \ +    frameworks/av/services/soundtrigger  LOCAL_MODULE:= mediaserver  LOCAL_32_BIT_ONLY := true diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp index a347951..af1c9e6 100644 --- a/media/mediaserver/main_mediaserver.cpp +++ b/media/mediaserver/main_mediaserver.cpp @@ -34,6 +34,7 @@  #include "MediaLogService.h"  #include "MediaPlayerService.h"  #include "AudioPolicyService.h" +#include "SoundTriggerHwService.h"  using namespace android; @@ -128,6 +129,7 @@ int main(int argc __unused, char** argv)          MediaPlayerService::instantiate();          CameraService::instantiate();          AudioPolicyService::instantiate(); +        SoundTriggerHwService::instantiate();          registerExtensions();          ProcessState::self()->startThreadPool();          IPCThreadState::self()->joinThreadPool(); diff --git a/services/soundtrigger/Android.mk b/services/soundtrigger/Android.mk new file mode 100644 index 0000000..b7ccaab --- /dev/null +++ b/services/soundtrigger/Android.mk @@ -0,0 +1,41 @@ +# Copyright 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +#      http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + + +ifeq ($(SOUND_TRIGGER_USE_STUB_MODULE), 1) +    LOCAL_CFLAGS += -DSOUND_TRIGGER_USE_STUB_MODULE +endif + +LOCAL_SRC_FILES:=               \ +    SoundTriggerHwService.cpp + +LOCAL_SHARED_LIBRARIES:= \ +    libui \ +    liblog \ +    libutils \ +    libbinder \ +    libcutils \ +    libhardware \ +    libsoundtrigger + +#LOCAL_C_INCLUDES += \ + + +LOCAL_MODULE:= libsoundtriggerservice + +include $(BUILD_SHARED_LIBRARY) diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp new file mode 100644 index 0000000..f09e79e --- /dev/null +++ b/services/soundtrigger/SoundTriggerHwService.cpp @@ -0,0 +1,566 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "SoundTriggerHwService" +//#define LOG_NDEBUG 0 + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <pthread.h> + +#include <binder/IServiceManager.h> +#include <binder/MemoryBase.h> +#include <binder/MemoryHeapBase.h> +#include <cutils/atomic.h> +#include <cutils/properties.h> +#include <hardware/hardware.h> +#include <utils/Errors.h> +#include <utils/Log.h> + +#include "SoundTriggerHwService.h" +#include <system/sound_trigger.h> +#include <hardware/sound_trigger.h> + +namespace android { + +#ifdef SOUND_TRIGGER_USE_STUB_MODULE +#define HW_MODULE_PREFIX "stub" +#else +#define HW_MODULE_PREFIX "primary" +#endif + +SoundTriggerHwService::SoundTriggerHwService() +    : BnSoundTriggerHwService(), +      mNextUniqueId(1) +{ +} + +void SoundTriggerHwService::onFirstRef() +{ +    const hw_module_t *mod; +    int rc; +    sound_trigger_hw_device *dev; + +    rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, HW_MODULE_PREFIX, &mod); +    if (rc != 0) { +        ALOGE("couldn't load sound trigger module %s.%s (%s)", +              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc)); +        return; +    } +    rc = sound_trigger_hw_device_open(mod, &dev); +    if (rc != 0) { +        ALOGE("couldn't open sound trigger hw device in %s.%s (%s)", +              SOUND_TRIGGER_HARDWARE_MODULE_ID, "primary", strerror(-rc)); +        return; +    } +    if (dev->common.version != SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) { +        ALOGE("wrong sound trigger hw device version %04x", dev->common.version); +        return; +    } + +    sound_trigger_module_descriptor descriptor; +    rc = dev->get_properties(dev, &descriptor.properties); +    if (rc != 0) { +        ALOGE("could not read implementation properties"); +        return; +    } +    descriptor.handle = +            (sound_trigger_module_handle_t)android_atomic_inc(&mNextUniqueId); +    ALOGI("loaded default module %s, handle %d", descriptor.properties.description, +                                                 descriptor.handle); + +    sp<ISoundTriggerClient> client; +    sp<Module> module = new Module(this, dev, descriptor, client); +    mModules.add(descriptor.handle, module); +    mCallbackThread = new CallbackThread(this); +} + +SoundTriggerHwService::~SoundTriggerHwService() +{ +    if (mCallbackThread != 0) { +        mCallbackThread->exit(); +    } +    for (size_t i = 0; i < mModules.size(); i++) { +        sound_trigger_hw_device_close(mModules.valueAt(i)->hwDevice()); +    } +} + +status_t SoundTriggerHwService::listModules(struct sound_trigger_module_descriptor *modules, +                             uint32_t *numModules) +{ +    ALOGV("listModules"); +    AutoMutex lock(mServiceLock); +    if (numModules == NULL || (*numModules != 0 && modules == NULL)) { +        return BAD_VALUE; +    } +    size_t maxModules = *numModules; +    *numModules = mModules.size(); +    for (size_t i = 0; i < mModules.size() && i < maxModules; i++) { +        modules[i] = mModules.valueAt(i)->descriptor(); +    } +    return NO_ERROR; +} + +status_t SoundTriggerHwService::attach(const sound_trigger_module_handle_t handle, +                        const sp<ISoundTriggerClient>& client, +                        sp<ISoundTrigger>& moduleInterface) +{ +    ALOGV("attach module %d", handle); +    AutoMutex lock(mServiceLock); +    moduleInterface.clear(); +    if (client == 0) { +        return BAD_VALUE; +    } +    ssize_t index = mModules.indexOfKey(handle); +    if (index < 0) { +        return BAD_VALUE; +    } +    sp<Module> module = mModules.valueAt(index); + +    module->setClient(client); +    client->asBinder()->linkToDeath(module); +    moduleInterface = module; + +    return NO_ERROR; +} + +void SoundTriggerHwService::detachModule(sp<Module> module) { +    AutoMutex lock(mServiceLock); +    ALOGV("detachModule"); +    module->clearClient(); +} + +static const int kDumpLockRetries = 50; +static const int kDumpLockSleep = 60000; + +static bool tryLock(Mutex& mutex) +{ +    bool locked = false; +    for (int i = 0; i < kDumpLockRetries; ++i) { +        if (mutex.tryLock() == NO_ERROR) { +            locked = true; +            break; +        } +        usleep(kDumpLockSleep); +    } +    return locked; +} + +status_t SoundTriggerHwService::dump(int fd, const Vector<String16>& args __unused) { +    String8 result; +    if (checkCallingPermission(String16("android.permission.DUMP")) == false) { +        result.appendFormat("Permission Denial: can't dump SoundTriggerHwService"); +        write(fd, result.string(), result.size()); +    } else { +        bool locked = tryLock(mServiceLock); +        // failed to lock - SoundTriggerHwService is probably deadlocked +        if (!locked) { +            result.append("SoundTriggerHwService may be deadlocked\n"); +            write(fd, result.string(), result.size()); +        } + +        if (locked) mServiceLock.unlock(); +    } +    return NO_ERROR; +} + +status_t SoundTriggerHwService::onTransact( +    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { +    return BnSoundTriggerHwService::onTransact(code, data, reply, flags); +} + + +// static +void SoundTriggerHwService::recognitionCallback(struct sound_trigger_recognition_event *event, +                                                void *cookie) +{ +    Module *module = (Module *)cookie; +    if (module == NULL) { +        return; +    } +    module->sendRecognitionEvent(event); +} + + +void SoundTriggerHwService::sendRecognitionEvent(const sp<RecognitionEvent>& event) +{ +    mCallbackThread->sendRecognitionEvent(event); +} + +void SoundTriggerHwService::onRecognitionEvent(const sp<RecognitionEvent>& event) +{ +    ALOGV("onRecognitionEvent"); +    sp<Module> module; +    { +        AutoMutex lock(mServiceLock); +        module = event->mModule.promote(); +        if (module == 0) { +            return; +        } +    } +    module->onRecognitionEvent(event->mEventMemory); +} + +// static +void SoundTriggerHwService::soundModelCallback(struct sound_trigger_model_event *event __unused, +                                               void *cookie) +{ +    Module *module = (Module *)cookie; + +} + +#undef LOG_TAG +#define LOG_TAG "SoundTriggerHwService::CallbackThread" + +SoundTriggerHwService::CallbackThread::CallbackThread(const wp<SoundTriggerHwService>& service) +    : mService(service) +{ +} + +SoundTriggerHwService::CallbackThread::~CallbackThread() +{ +    mEventQueue.clear(); +} + +void SoundTriggerHwService::CallbackThread::onFirstRef() +{ +    run("soundTrigger cbk", ANDROID_PRIORITY_URGENT_AUDIO); +} + +bool SoundTriggerHwService::CallbackThread::threadLoop() +{ +    while (!exitPending()) { +        sp<RecognitionEvent> event; +        sp<SoundTriggerHwService> service; +        { +            Mutex::Autolock _l(mCallbackLock); +            while (mEventQueue.isEmpty() && !exitPending()) { +                ALOGV("CallbackThread::threadLoop() sleep"); +                mCallbackCond.wait(mCallbackLock); +                ALOGV("CallbackThread::threadLoop() wake up"); +            } +            if (exitPending()) { +                break; +            } +            event = mEventQueue[0]; +            mEventQueue.removeAt(0); +            service = mService.promote(); +        } +        if (service != 0) { +            service->onRecognitionEvent(event); +        } +    } +    return false; +} + +void SoundTriggerHwService::CallbackThread::exit() +{ +    Mutex::Autolock _l(mCallbackLock); +    requestExit(); +    mCallbackCond.broadcast(); +} + +void SoundTriggerHwService::CallbackThread::sendRecognitionEvent( +                        const sp<SoundTriggerHwService::RecognitionEvent>& event) +{ +    AutoMutex lock(mCallbackLock); +    mEventQueue.add(event); +    mCallbackCond.signal(); +} + +SoundTriggerHwService::RecognitionEvent::RecognitionEvent( +                                            sp<IMemory> eventMemory, +                                            wp<Module> module) +    : mEventMemory(eventMemory), mModule(module) +{ +} + +SoundTriggerHwService::RecognitionEvent::~RecognitionEvent() +{ +} + +#undef LOG_TAG +#define LOG_TAG "SoundTriggerHwService::Module" + +SoundTriggerHwService::Module::Module(const sp<SoundTriggerHwService>& service, +                                      sound_trigger_hw_device* hwDevice, +                                      sound_trigger_module_descriptor descriptor, +                                      const sp<ISoundTriggerClient>& client) + : mService(service), mHwDevice(hwDevice), mDescriptor(descriptor), +   mClient(client) +{ +} + +SoundTriggerHwService::Module::~Module() { +} + +void SoundTriggerHwService::Module::detach() { +    ALOGV("detach()"); +    { +        AutoMutex lock(mLock); +        for (size_t i = 0; i < mModels.size(); i++) { +            sp<Model> model = mModels.valueAt(i); +            ALOGV("detach() unloading model %d", model->mHandle); +            if (model->mState == Model::STATE_ACTIVE) { +                mHwDevice->stop_recognition(mHwDevice, model->mHandle); +                model->deallocateMemory(); +            } +            mHwDevice->unload_sound_model(mHwDevice, model->mHandle); +        } +        mModels.clear(); +    } +    if (mClient != 0) { +        mClient->asBinder()->unlinkToDeath(this); +    } +    sp<SoundTriggerHwService> service = mService.promote(); +    if (service == 0) { +        return; +    } +    service->detachModule(this); +} + +status_t SoundTriggerHwService::Module::loadSoundModel(const sp<IMemory>& modelMemory, +                                sound_model_handle_t *handle) +{ +    ALOGV("loadSoundModel() handle"); + +    if (modelMemory == 0 || modelMemory->pointer() == NULL) { +        ALOGE("loadSoundModel() modelMemory is 0 or has NULL pointer()"); +        return BAD_VALUE; +    } +    struct sound_trigger_sound_model *sound_model = +            (struct sound_trigger_sound_model *)modelMemory->pointer(); + +    AutoMutex lock(mLock); +    status_t status = mHwDevice->load_sound_model(mHwDevice, +                                                  sound_model, +                                                  SoundTriggerHwService::soundModelCallback, +                                                  this, +                                                  handle); +    if (status == NO_ERROR) { +        mModels.replaceValueFor(*handle, new Model(*handle)); +    } + +    return status; +} + +status_t SoundTriggerHwService::Module::unloadSoundModel(sound_model_handle_t handle) +{ +    ALOGV("unloadSoundModel() model handle %d", handle); + +    AutoMutex lock(mLock); +    ssize_t index = mModels.indexOfKey(handle); +    if (index < 0) { +        return BAD_VALUE; +    } +    mModels.removeItem(handle); + +    return mHwDevice->unload_sound_model(mHwDevice, handle); +} + +status_t SoundTriggerHwService::Module::startRecognition(sound_model_handle_t handle, +                                  const sp<IMemory>& dataMemory) +{ +    ALOGV("startRecognition() model handle %d", handle); + +    if (dataMemory != 0 && dataMemory->pointer() == NULL) { +        ALOGE("startRecognition() dataMemory is non-0 but has NULL pointer()"); +        return BAD_VALUE; + +    } +    AutoMutex lock(mLock); +    sp<Model> model = getModel(handle); +    if (model == 0) { +        return BAD_VALUE; +    } + +    if (model->mState == Model::STATE_ACTIVE) { +        return INVALID_OPERATION; +    } +    model->mState = Model::STATE_ACTIVE; + +    char *data = NULL; +    unsigned int data_size = 0; +    if (dataMemory != 0 && dataMemory->size() != 0) { +        data_size = (unsigned int)dataMemory->size(); +        data = (char *)dataMemory->pointer(); +        ALOGV("startRecognition() data size %d data %d - %d", +                      data_size, data[0], data[data_size - 1]); +    } + +    //TODO: get capture handle and device from audio policy service +    audio_io_handle_t capture_handle = 0; +    return mHwDevice->start_recognition(mHwDevice, handle, capture_handle, AUDIO_DEVICE_NONE, +                                        SoundTriggerHwService::recognitionCallback, +                                        this, +                                        data_size, +                                        data); +} + +status_t SoundTriggerHwService::Module::stopRecognition(sound_model_handle_t handle) +{ +    ALOGV("stopRecognition() model handle %d", handle); + +    AutoMutex lock(mLock); +    sp<Model> model = getModel(handle); +    if (model == 0) { +        return BAD_VALUE; +    } + +    if (model->mState != Model::STATE_ACTIVE) { +        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) +{ +    ALOGV("Module::onRecognitionEvent"); + +    AutoMutex lock(mLock); + +    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(); +} + +sp<SoundTriggerHwService::Model> SoundTriggerHwService::Module::getModel( +        sound_model_handle_t handle) +{ +    sp<Model> model; +    ssize_t index = mModels.indexOfKey(handle); +    if (index >= 0) { +        model = mModels.valueAt(index); +    } +    return model; +} + +void SoundTriggerHwService::Module::binderDied( +    const wp<IBinder> &who __unused) { +    ALOGW("client binder died for module %d", mDescriptor.handle); +    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")) +{ + +} + + +sp<IMemory> SoundTriggerHwService::Model::allocateMemory(size_t size) +{ +    sp<IMemory> memory; +    if (mMemoryDealer->getMemoryHeap()->getSize() < size) { +        mMemoryDealer = new MemoryDealer(size, "SoundTriggerHwService::Event"); +    } +    memory = mMemoryDealer->allocate(size); +    return memory; +} + +void SoundTriggerHwService::Model::deallocateMemory() +{ +    mMemoryDealer->deallocate(0); +} + +status_t SoundTriggerHwService::Module::dump(int fd __unused, +                                             const Vector<String16>& args __unused) { +    String8 result; +    return NO_ERROR; +} + +}; // namespace android diff --git a/services/soundtrigger/SoundTriggerHwService.h b/services/soundtrigger/SoundTriggerHwService.h new file mode 100644 index 0000000..377f2a1 --- /dev/null +++ b/services/soundtrigger/SoundTriggerHwService.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + *      http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_HAL_SERVICE_H +#define ANDROID_HARDWARE_SOUNDTRIGGER_HAL_SERVICE_H + +#include <utils/Vector.h> +//#include <binder/AppOpsManager.h> +#include <binder/MemoryDealer.h> +#include <binder/BinderService.h> +#include <binder/IAppOpsCallback.h> +#include <soundtrigger/ISoundTriggerHwService.h> +#include <soundtrigger/ISoundTrigger.h> +#include <soundtrigger/ISoundTriggerClient.h> +#include <system/sound_trigger.h> +#include <hardware/sound_trigger.h> + +namespace android { + +class MemoryHeapBase; + +class SoundTriggerHwService : +    public BinderService<SoundTriggerHwService>, +    public BnSoundTriggerHwService +{ +    friend class BinderService<SoundTriggerHwService>; +public: +    class Module; + +    static char const* getServiceName() { return "media.sound_trigger_hw"; } + +                        SoundTriggerHwService(); +    virtual             ~SoundTriggerHwService(); + +    // ISoundTriggerHwService +    virtual status_t listModules(struct sound_trigger_module_descriptor *modules, +                                 uint32_t *numModules); + +    virtual status_t attach(const sound_trigger_module_handle_t handle, +                            const sp<ISoundTriggerClient>& client, +                            sp<ISoundTrigger>& module); + +    virtual status_t    onTransact(uint32_t code, const Parcel& data, +                                   Parcel* reply, uint32_t flags); + +    virtual status_t    dump(int fd, const Vector<String16>& args); + +    class Model : public RefBase { +     public: + +        enum { +            STATE_IDLE, +            STATE_ACTIVE +        }; + +        Model(sound_model_handle_t handle); +        ~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; +    }; + +    class Module : public virtual RefBase, +                   public BnSoundTrigger, +                   public IBinder::DeathRecipient     { +    public: + +       Module(const sp<SoundTriggerHwService>& service, +              sound_trigger_hw_device* hwDevice, +              sound_trigger_module_descriptor descriptor, +              const sp<ISoundTriggerClient>& client); + +       virtual ~Module(); + +       virtual void detach(); + +       virtual status_t loadSoundModel(const sp<IMemory>& 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<IMemory>& dataMemory); +       virtual status_t stopRecognition(sound_model_handle_t handle); + +       virtual status_t dump(int fd, const Vector<String16>& args); + + +       sound_trigger_hw_device *hwDevice() const { return mHwDevice; } +       struct sound_trigger_module_descriptor descriptor() { return mDescriptor; } +       void setClient(sp<ISoundTriggerClient> client) { mClient = client; } +       void clearClient() { mClient.clear(); } +       sp<ISoundTriggerClient> client() { return mClient; } + +       void sendRecognitionEvent(struct sound_trigger_recognition_event *event); +       void onRecognitionEvent(sp<IMemory> eventMemory); + +       sp<Model> getModel(sound_model_handle_t handle); + +       // 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; +    }; // 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: + +        CallbackThread(const wp<SoundTriggerHwService>& service); + +        virtual             ~CallbackThread(); + +        // Thread virtuals +        virtual bool        threadLoop(); + +        // RefBase +        virtual void        onFirstRef(); + +                void        exit(); +                void        sendRecognitionEvent(const sp<RecognitionEvent>& event); + +    private: +        wp<SoundTriggerHwService>   mService; +        Condition                   mCallbackCond; +        Mutex                       mCallbackLock; +        Vector< sp<RecognitionEvent> > mEventQueue; +    }; + +    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); + +    static void soundModelCallback(struct sound_trigger_model_event *event, void *cookie); + +private: + +    virtual void onFirstRef(); + +    Mutex               mServiceLock; +    volatile int32_t    mNextUniqueId; +    DefaultKeyedVector< sound_trigger_module_handle_t, sp<Module> >     mModules; +    sp<CallbackThread>  mCallbackThread; +}; + +} // namespace android + +#endif // ANDROID_HARDWARE_SOUNDTRIGGER_HAL_SERVICE_H diff --git a/soundtrigger/Android.mk b/soundtrigger/Android.mk new file mode 100644 index 0000000..d91c4c2 --- /dev/null +++ b/soundtrigger/Android.mk @@ -0,0 +1,38 @@ +# Copyright 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +#      http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ +	SoundTrigger.cpp \ +	ISoundTrigger.cpp \ +	ISoundTriggerClient.cpp \ +	ISoundTriggerHwService.cpp + +LOCAL_SHARED_LIBRARIES := \ +	libcutils \ +	libutils \ +	liblog \ +	libbinder \ +	libhardware + +#LOCAL_C_INCLUDES += \ +	system/media/camera/include \ +	system/media/private/camera/include + +LOCAL_MODULE:= libsoundtrigger + +include $(BUILD_SHARED_LIBRARY) diff --git a/soundtrigger/ISoundTrigger.cpp b/soundtrigger/ISoundTrigger.cpp new file mode 100644 index 0000000..42280d1 --- /dev/null +++ b/soundtrigger/ISoundTrigger.cpp @@ -0,0 +1,177 @@ +/* +** +** Copyright 2014, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +**     http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "ISoundTrigger" +#include <utils/Log.h> +#include <utils/Errors.h> +#include <binder/IMemory.h> +#include <soundtrigger/ISoundTrigger.h> +#include <soundtrigger/ISoundTriggerHwService.h> +#include <soundtrigger/ISoundTriggerClient.h> +#include <system/sound_trigger.h> + +namespace android { + +enum { +    DETACH = IBinder::FIRST_CALL_TRANSACTION, +    LOAD_SOUND_MODEL, +    UNLOAD_SOUND_MODEL, +    START_RECOGNITION, +    STOP_RECOGNITION, +}; + +class BpSoundTrigger: public BpInterface<ISoundTrigger> +{ +public: +    BpSoundTrigger(const sp<IBinder>& impl) +        : BpInterface<ISoundTrigger>(impl) +    { +    } + +    void detach() +    { +        ALOGV("detach"); +        Parcel data, reply; +        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor()); +        remote()->transact(DETACH, data, &reply); +    } + +    status_t loadSoundModel(const sp<IMemory>&  modelMemory, +                                    sound_model_handle_t *handle) +    { +        if (modelMemory == 0 || handle == NULL) { +            return BAD_VALUE; +        } +        Parcel data, reply; +        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor()); +        data.writeStrongBinder(modelMemory->asBinder()); +        status_t status = remote()->transact(LOAD_SOUND_MODEL, data, &reply); +        if (status != NO_ERROR || +                (status = (status_t)reply.readInt32()) != NO_ERROR) { +            return status; +        } +        reply.read(handle, sizeof(sound_model_handle_t)); +        return status; +    } + +    virtual status_t unloadSoundModel(sound_model_handle_t handle) +    { +        Parcel data, reply; +        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor()); +        data.write(&handle, sizeof(sound_model_handle_t)); +        status_t status = remote()->transact(UNLOAD_SOUND_MODEL, data, &reply); +        if (status != NO_ERROR) { +            status = (status_t)reply.readInt32(); +        } +        return status; +    } + +    virtual status_t startRecognition(sound_model_handle_t handle, +                                      const sp<IMemory>& dataMemory) +    { +        Parcel data, reply; +        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor()); +        data.write(&handle, sizeof(sound_model_handle_t)); +        if (dataMemory == 0) { +            data.writeInt32(0); +        } else { +            data.writeInt32(dataMemory->size()); +        } +        data.writeStrongBinder(dataMemory->asBinder()); +        status_t status = remote()->transact(START_RECOGNITION, data, &reply); +        if (status != NO_ERROR) { +            status = (status_t)reply.readInt32(); +        } +        return status; +    } + +    virtual status_t stopRecognition(sound_model_handle_t handle) +    { +        Parcel data, reply; +        data.writeInterfaceToken(ISoundTrigger::getInterfaceDescriptor()); +        data.write(&handle, sizeof(sound_model_handle_t)); +        status_t status = remote()->transact(STOP_RECOGNITION, data, &reply); +        if (status != NO_ERROR) { +            status = (status_t)reply.readInt32(); +        } +        return status; +    } + +}; + +IMPLEMENT_META_INTERFACE(SoundTrigger, "android.hardware.ISoundTrigger"); + +// ---------------------------------------------------------------------- + +status_t BnSoundTrigger::onTransact( +    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ +    switch(code) { +        case DETACH: { +            ALOGV("DETACH"); +            CHECK_INTERFACE(ISoundTrigger, data, reply); +            detach(); +            return NO_ERROR; +        } break; +        case LOAD_SOUND_MODEL: { +            CHECK_INTERFACE(ISoundTrigger, data, reply); +            sp<IMemory> modelMemory = interface_cast<IMemory>( +                data.readStrongBinder()); +            sound_model_handle_t handle; +            status_t status = loadSoundModel(modelMemory, &handle); +            reply->writeInt32(status); +            if (status == NO_ERROR) { +                reply->write(&handle, sizeof(sound_model_handle_t)); +            } +            return NO_ERROR; +        } +        case UNLOAD_SOUND_MODEL: { +            CHECK_INTERFACE(ISoundTrigger, data, reply); +            sound_model_handle_t handle; +            data.read(&handle, sizeof(sound_model_handle_t)); +            status_t status = unloadSoundModel(handle); +            reply->writeInt32(status); +            return NO_ERROR; +        } +        case START_RECOGNITION: { +            CHECK_INTERFACE(ISoundTrigger, data, reply); +            sound_model_handle_t handle; +            data.read(&handle, sizeof(sound_model_handle_t)); +            sp<IMemory> dataMemory; +            if (data.readInt32() != 0) { +                dataMemory = interface_cast<IMemory>(data.readStrongBinder()); +            } +            status_t status = startRecognition(handle, dataMemory); +            reply->writeInt32(status); +            return NO_ERROR; +        } +        case STOP_RECOGNITION: { +            CHECK_INTERFACE(ISoundTrigger, data, reply); +            sound_model_handle_t handle; +            data.read(&handle, sizeof(sound_model_handle_t)); +            status_t status = stopRecognition(handle); +            reply->writeInt32(status); +            return NO_ERROR; +        } +        default: +            return BBinder::onTransact(code, data, reply, flags); +    } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/soundtrigger/ISoundTriggerClient.cpp b/soundtrigger/ISoundTriggerClient.cpp new file mode 100644 index 0000000..1d0c0ec --- /dev/null +++ b/soundtrigger/ISoundTriggerClient.cpp @@ -0,0 +1,75 @@ +/* +** +** Copyright 2014, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +**     http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdint.h> +#include <sys/types.h> +#include <binder/IMemory.h> +#include <binder/Parcel.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <soundtrigger/ISoundTriggerClient.h> + +namespace android { + +enum { +    ON_RECOGNITION_EVENT = IBinder::FIRST_CALL_TRANSACTION, +}; + +class BpSoundTriggerClient: public BpInterface<ISoundTriggerClient> +{ + +public: +    BpSoundTriggerClient(const sp<IBinder>& impl) +        : BpInterface<ISoundTriggerClient>(impl) +    { +    } + +    virtual void onRecognitionEvent(const sp<IMemory>& eventMemory) +    { +        Parcel data, reply; +        data.writeInterfaceToken(ISoundTriggerClient::getInterfaceDescriptor()); +        data.writeStrongBinder(eventMemory->asBinder()); +        remote()->transact(ON_RECOGNITION_EVENT, +                           data, +                           &reply); +    } +}; + +IMPLEMENT_META_INTERFACE(SoundTriggerClient, +                         "android.hardware.ISoundTriggerClient"); + +// ---------------------------------------------------------------------- + +status_t BnSoundTriggerClient::onTransact( +    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ +    switch(code) { +        case ON_RECOGNITION_EVENT: { +            CHECK_INTERFACE(ISoundTriggerClient, data, reply); +            sp<IMemory> eventMemory = interface_cast<IMemory>( +                data.readStrongBinder()); +            onRecognitionEvent(eventMemory); +            return NO_ERROR; +        } break; +        default: +            return BBinder::onTransact(code, data, reply, flags); +    } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/soundtrigger/ISoundTriggerHwService.cpp b/soundtrigger/ISoundTriggerHwService.cpp new file mode 100644 index 0000000..c9a0c24 --- /dev/null +++ b/soundtrigger/ISoundTriggerHwService.cpp @@ -0,0 +1,150 @@ +/* +** +** Copyright 2014, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +**     http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "BpSoundTriggerHwService" +//#define LOG_NDEBUG 0 + +#include <utils/Log.h> +#include <utils/Errors.h> + +#include <stdint.h> +#include <sys/types.h> +#include <binder/IMemory.h> +#include <binder/Parcel.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> + +#include <soundtrigger/ISoundTriggerHwService.h> +#include <soundtrigger/ISoundTrigger.h> +#include <soundtrigger/ISoundTriggerClient.h> + +namespace android { + +enum { +    LIST_MODULES = IBinder::FIRST_CALL_TRANSACTION, +    ATTACH, +}; + +class BpSoundTriggerHwService: public BpInterface<ISoundTriggerHwService> +{ +public: +    BpSoundTriggerHwService(const sp<IBinder>& impl) +        : BpInterface<ISoundTriggerHwService>(impl) +    { +    } + +    virtual status_t listModules(struct sound_trigger_module_descriptor *modules, +                                 uint32_t *numModules) +    { +        if (numModules == NULL || (*numModules != 0 && modules == NULL)) { +            return BAD_VALUE; +        } +        Parcel data, reply; +        data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor()); +        unsigned int numModulesReq = (modules == NULL) ? 0 : *numModules; +        data.writeInt32(numModulesReq); +        status_t status = remote()->transact(LIST_MODULES, data, &reply); +        if (status == NO_ERROR) { +            status = (status_t)reply.readInt32(); +            *numModules = (unsigned int)reply.readInt32(); +        } +        ALOGV("listModules() status %d got *numModules %d", status, *numModules); +        if (status == NO_ERROR) { +            if (numModulesReq > *numModules) { +                numModulesReq = *numModules; +            } +            if (numModulesReq > 0) { +                reply.read(modules, numModulesReq * sizeof(struct sound_trigger_module_descriptor)); +            } +        } +        return status; +    } + +    virtual status_t attach(const sound_trigger_module_handle_t handle, +                            const sp<ISoundTriggerClient>& client, +                            sp<ISoundTrigger>& module) +    { +        Parcel data, reply; +        data.writeInterfaceToken(ISoundTriggerHwService::getInterfaceDescriptor()); +        data.write(&handle, sizeof(sound_trigger_module_handle_t)); +        data.writeStrongBinder(client->asBinder()); +        remote()->transact(ATTACH, data, &reply); +        status_t status = reply.readInt32(); +        if (reply.readInt32() != 0) { +            module = interface_cast<ISoundTrigger>(reply.readStrongBinder()); +        } +        return status; +    } + +}; + +IMPLEMENT_META_INTERFACE(SoundTriggerHwService, "android.hardware.ISoundTriggerHwService"); + +// ---------------------------------------------------------------------- + +status_t BnSoundTriggerHwService::onTransact( +    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ +    switch(code) { +        case LIST_MODULES: { +            CHECK_INTERFACE(ISoundTriggerHwService, data, reply); +            unsigned int numModulesReq = data.readInt32(); +            unsigned int numModules = numModulesReq; +            struct sound_trigger_module_descriptor *modules = +                    (struct sound_trigger_module_descriptor *)calloc(numModulesReq, +                                                   sizeof(struct sound_trigger_module_descriptor)); +            status_t status = listModules(modules, &numModules); +            reply->writeInt32(status); +            reply->writeInt32(numModules); +            ALOGV("LIST_MODULES status %d got numModules %d", status, numModules); + +            if (status == NO_ERROR) { +                if (numModulesReq > numModules) { +                    numModulesReq = numModules; +                } +                reply->write(modules, +                             numModulesReq * sizeof(struct sound_trigger_module_descriptor)); +            } +            free(modules); +            return NO_ERROR; +        } + +        case ATTACH: { +            CHECK_INTERFACE(ISoundTriggerHwService, data, reply); +            sound_trigger_module_handle_t handle; +            data.read(&handle, sizeof(sound_trigger_module_handle_t)); +            sp<ISoundTriggerClient> client = +                    interface_cast<ISoundTriggerClient>(data.readStrongBinder()); +            sp<ISoundTrigger> module; +            status_t status = attach(handle, client, module); +            reply->writeInt32(status); +            if (module != 0) { +                reply->writeInt32(1); +                reply->writeStrongBinder(module->asBinder()); +            } else { +                reply->writeInt32(0); +            } +            return NO_ERROR; +        } break; +        default: +            return BBinder::onTransact(code, data, reply, flags); +    } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/soundtrigger/SoundTrigger.cpp b/soundtrigger/SoundTrigger.cpp new file mode 100644 index 0000000..e43acd0 --- /dev/null +++ b/soundtrigger/SoundTrigger.cpp @@ -0,0 +1,253 @@ +/* +** +** Copyright (C) 2014, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +**     http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "SoundTrigger" +//#define LOG_NDEBUG 0 + +#include <utils/Log.h> +#include <utils/threads.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> +#include <binder/IMemory.h> + +#include <soundtrigger/SoundTrigger.h> +#include <soundtrigger/ISoundTrigger.h> +#include <soundtrigger/ISoundTriggerHwService.h> +#include <soundtrigger/ISoundTriggerClient.h> +#include <soundtrigger/SoundTriggerCallback.h> + +namespace android { + +namespace { +    sp<ISoundTriggerHwService> gSoundTriggerHwService; +    const int                  kSoundTriggerHwServicePollDelay = 500000; // 0.5s +    const char*                kSoundTriggerHwServiceName      = "media.sound_trigger_hw"; +    Mutex                      gLock; + +    class DeathNotifier : public IBinder::DeathRecipient +    { +    public: +        DeathNotifier() { +        } + +        virtual void binderDied(const wp<IBinder>& who __unused) { +            ALOGV("binderDied"); +            Mutex::Autolock _l(gLock); +            gSoundTriggerHwService.clear(); +            ALOGW("Sound trigger service died!"); +        } +    }; + +    sp<DeathNotifier>         gDeathNotifier; +}; // namespace anonymous + +const sp<ISoundTriggerHwService>& SoundTrigger::getSoundTriggerHwService() +{ +    Mutex::Autolock _l(gLock); +    if (gSoundTriggerHwService.get() == 0) { +        sp<IServiceManager> sm = defaultServiceManager(); +        sp<IBinder> binder; +        do { +            binder = sm->getService(String16(kSoundTriggerHwServiceName)); +            if (binder != 0) { +                break; +            } +            ALOGW("SoundTriggerHwService not published, waiting..."); +            usleep(kSoundTriggerHwServicePollDelay); +        } while(true); +        if (gDeathNotifier == NULL) { +            gDeathNotifier = new DeathNotifier(); +        } +        binder->linkToDeath(gDeathNotifier); +        gSoundTriggerHwService = interface_cast<ISoundTriggerHwService>(binder); +    } +    ALOGE_IF(gSoundTriggerHwService == 0, "no SoundTriggerHwService!?"); +    return gSoundTriggerHwService; +} + +// Static methods +status_t SoundTrigger::listModules(struct sound_trigger_module_descriptor *modules, +                                 uint32_t *numModules) +{ +    ALOGV("listModules()"); +    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService(); +    if (service == 0) { +        return NO_INIT; +    } +    return service->listModules(modules, numModules); +} + +sp<SoundTrigger> SoundTrigger::attach(const sound_trigger_module_handle_t module, +                                            const sp<SoundTriggerCallback>& callback) +{ +    ALOGV("attach()"); +    sp<SoundTrigger> soundTrigger; +    const sp<ISoundTriggerHwService>& service = getSoundTriggerHwService(); +    if (service == 0) { +        return soundTrigger; +    } +    soundTrigger = new SoundTrigger(module, callback); +    status_t status = service->attach(module, soundTrigger, soundTrigger->mISoundTrigger); + +    if (status == NO_ERROR && soundTrigger->mISoundTrigger != 0) { +        soundTrigger->mISoundTrigger->asBinder()->linkToDeath(soundTrigger); +    } else { +        ALOGW("Error %d connecting to sound trigger service", status); +        soundTrigger.clear(); +    } +    return soundTrigger; +} + + +// SoundTrigger +SoundTrigger::SoundTrigger(sound_trigger_module_handle_t module, +                                 const sp<SoundTriggerCallback>& callback) +    : mModule(module), mCallback(callback) +{ +} + +SoundTrigger::~SoundTrigger() +{ +    if (mISoundTrigger != 0) { +        mISoundTrigger->detach(); +    } +} + + +void SoundTrigger::detach() { +    ALOGV("detach()"); +    Mutex::Autolock _l(mLock); +    mCallback.clear(); +    if (mISoundTrigger != 0) { +        mISoundTrigger->detach(); +        mISoundTrigger->asBinder()->unlinkToDeath(this); +        mISoundTrigger = 0; +    } +} + +status_t SoundTrigger::loadSoundModel(const sp<IMemory>& modelMemory, +                                sound_model_handle_t *handle) +{ +    Mutex::Autolock _l(mLock); +    if (mISoundTrigger == 0) { +        return NO_INIT; +    } + +    return mISoundTrigger->loadSoundModel(modelMemory, handle); +} + +status_t SoundTrigger::unloadSoundModel(sound_model_handle_t handle) +{ +    Mutex::Autolock _l(mLock); +    if (mISoundTrigger == 0) { +        return NO_INIT; +    } +    return mISoundTrigger->unloadSoundModel(handle); +} + +status_t SoundTrigger::startRecognition(sound_model_handle_t handle, +                                        const sp<IMemory>& dataMemory) +{ +    Mutex::Autolock _l(mLock); +    if (mISoundTrigger == 0) { +        return NO_INIT; +    } +    return mISoundTrigger->startRecognition(handle, dataMemory); +} + +status_t SoundTrigger::stopRecognition(sound_model_handle_t handle) +{ +    Mutex::Autolock _l(mLock); +    if (mISoundTrigger == 0) { +        return NO_INIT; +    } +    return mISoundTrigger->stopRecognition(handle); +} + +// BpSoundTriggerClient +void SoundTrigger::onRecognitionEvent(const sp<IMemory>& eventMemory) +{ +    Mutex::Autolock _l(mLock); +    if (eventMemory == 0 || eventMemory->pointer() == NULL) { +        return; +    } + +    if (mCallback != 0) { +        mCallback->onRecognitionEvent( +                (struct sound_trigger_recognition_event *)eventMemory->pointer()); +    } +} + + +//IBinder::DeathRecipient +void SoundTrigger::binderDied(const wp<IBinder>& who __unused) { +    Mutex::Autolock _l(mLock); +    ALOGW("SoundTrigger server binder Died "); +    mISoundTrigger = 0; +    if (mCallback != 0) { +        mCallback->onServiceDied(); +    } +} + +status_t SoundTrigger::stringToGuid(const char *str, sound_trigger_uuid_t *guid) +{ +    if (str == NULL || guid == NULL) { +        return BAD_VALUE; +    } + +    int tmp[10]; + +    if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", +            tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) { +        return BAD_VALUE; +    } +    guid->timeLow = (uint32_t)tmp[0]; +    guid->timeMid = (uint16_t)tmp[1]; +    guid->timeHiAndVersion = (uint16_t)tmp[2]; +    guid->clockSeq = (uint16_t)tmp[3]; +    guid->node[0] = (uint8_t)tmp[4]; +    guid->node[1] = (uint8_t)tmp[5]; +    guid->node[2] = (uint8_t)tmp[6]; +    guid->node[3] = (uint8_t)tmp[7]; +    guid->node[4] = (uint8_t)tmp[8]; +    guid->node[5] = (uint8_t)tmp[9]; + +    return NO_ERROR; +} + +status_t SoundTrigger::guidToString(const sound_trigger_uuid_t *guid, char *str, size_t maxLen) +{ +    if (guid == NULL || str == NULL) { +        return BAD_VALUE; +    } + +    snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x", +            guid->timeLow, +            guid->timeMid, +            guid->timeHiAndVersion, +            guid->clockSeq, +            guid->node[0], +            guid->node[1], +            guid->node[2], +            guid->node[3], +            guid->node[4], +            guid->node[5]); + +    return NO_ERROR; +} + +}; // namespace android  | 
