summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drm/mediadrm/plugins/clearkey/DrmPlugin.h4
-rw-r--r--drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp6
-rw-r--r--drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h2
-rw-r--r--include/media/AudioSystem.h6
-rw-r--r--include/media/IAudioPolicyService.h6
-rw-r--r--include/media/IDrm.h2
-rw-r--r--include/media/stagefright/MediaCodecSource.h3
-rw-r--r--include/soundtrigger/ISoundTriggerClient.h4
-rw-r--r--include/soundtrigger/ISoundTriggerHwService.h2
-rw-r--r--include/soundtrigger/SoundTrigger.h8
-rw-r--r--include/soundtrigger/SoundTriggerCallback.h4
-rw-r--r--media/libmedia/AudioSystem.cpp15
-rw-r--r--media/libmedia/IAudioPolicyService.cpp67
-rw-r--r--media/libmedia/IDrm.cpp20
-rw-r--r--media/libmediaplayerservice/Drm.cpp17
-rw-r--r--media/libmediaplayerservice/Drm.h2
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.cpp276
-rw-r--r--media/libmediaplayerservice/nuplayer/GenericSource.h13
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp23
-rw-r--r--media/libstagefright/AudioSource.cpp4
-rw-r--r--media/libstagefright/MediaCodecSource.cpp74
-rw-r--r--media/libstagefright/Utils.cpp5
-rw-r--r--services/audioflinger/AudioFlinger.cpp6
-rw-r--r--services/audioflinger/AudioMixer.cpp103
-rw-r--r--services/audioflinger/AudioMixer.h4
-rw-r--r--services/audioflinger/StateQueue.cpp16
-rw-r--r--services/audioflinger/StateQueue.h4
-rw-r--r--services/audiopolicy/Android.mk5
-rw-r--r--services/audiopolicy/AudioPolicyClientImpl.cpp1
-rw-r--r--services/audiopolicy/AudioPolicyInterface.h5
-rw-r--r--services/audiopolicy/AudioPolicyInterfaceImpl.cpp20
-rw-r--r--services/audiopolicy/AudioPolicyInterfaceImplLegacy.cpp15
-rw-r--r--services/audiopolicy/AudioPolicyManager.cpp123
-rw-r--r--services/audiopolicy/AudioPolicyManager.h34
-rw-r--r--services/audiopolicy/AudioPolicyService.h6
-rw-r--r--services/soundtrigger/Android.mk8
-rw-r--r--services/soundtrigger/SoundTriggerHwService.cpp493
-rw-r--r--services/soundtrigger/SoundTriggerHwService.h71
-rw-r--r--soundtrigger/ISoundTriggerClient.cpp35
-rw-r--r--soundtrigger/ISoundTriggerHwService.cpp20
-rw-r--r--soundtrigger/SoundTrigger.cpp35
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> &notify);
- 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) {