Interface between audio server and vibrator service

The haptic playback should be controlled by vibrator service. Via the
interface, audio server could notify vibrator service about starting or
stopping haptic playback and get vibrator intensity from vibrator
service. Vibrator service could call mute/unmute to control the haptic
playback.

Test: Manually
Change-Id: Iad24813977e4dea0d67a91f8f8b390a016ce4ca2
gugelfrei
jiabin 6 years ago committed by Eric Laurent
parent 77270b8805
commit 57303cc431

@ -19,7 +19,8 @@ LOCAL_SHARED_LIBRARIES := \
libnbaio \
libnblog \
libsoundtriggerservice \
libutils
libutils \
libvibrator
# TODO oboeservice is the old folder name for aaudioservice. It will be changed.
LOCAL_C_INCLUDES := \

@ -38,7 +38,8 @@ LOCAL_SHARED_LIBRARIES := \
libpowermanager \
libmediautils \
libmemunreachable \
libmedia_helper
libmedia_helper \
libvibrator
LOCAL_STATIC_LIBRARIES := \
libcpustats \

@ -27,6 +27,7 @@
#include <sys/time.h>
#include <sys/resource.h>
#include <android/os/IExternalVibratorService.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
@ -122,6 +123,21 @@ static void sMediaLogInit()
}
}
// Keep a strong reference to external vibrator service
static sp<os::IExternalVibratorService> sExternalVibratorService;
static sp<os::IExternalVibratorService> getExternalVibratorService() {
if (sExternalVibratorService == 0) {
sp <IBinder> binder = defaultServiceManager()->getService(
String16("external_vibrator_service"));
if (binder != 0) {
sExternalVibratorService =
interface_cast<os::IExternalVibratorService>(binder);
}
}
return sExternalVibratorService;
}
// ----------------------------------------------------------------------------
std::string formatToString(audio_format_t format) {
@ -318,6 +334,27 @@ status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t di
return ret;
}
/* static */
int AudioFlinger::onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration) {
sp<os::IExternalVibratorService> evs = getExternalVibratorService();
if (evs != 0) {
int32_t ret;
binder::Status status = evs->onExternalVibrationStart(*externalVibration, &ret);
if (status.isOk()) {
return ret;
}
}
return AudioMixer::HAPTIC_SCALE_NONE;
}
/* static */
void AudioFlinger::onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration) {
sp<os::IExternalVibratorService> evs = getExternalVibratorService();
if (evs != 0) {
evs->onExternalVibrationStop(*externalVibration);
}
}
static const char * const audio_interfaces[] = {
AUDIO_HARDWARE_MODULE_ID_PRIMARY,
AUDIO_HARDWARE_MODULE_ID_A2DP,

@ -30,6 +30,7 @@
#include <sys/types.h>
#include <limits.h>
#include <android/os/BnExternalVibrationController.h>
#include <android-base/macros.h>
#include <cutils/atomic.h>
@ -84,6 +85,8 @@
#include <private/media/AudioEffectShared.h>
#include <private/media/AudioTrackShared.h>
#include <vibrator/ExternalVibration.h>
#include "android/media/BnAudioRecord.h"
namespace android {
@ -284,6 +287,9 @@ public:
const sp<MmapStreamCallback>& callback,
sp<MmapStreamInterface>& interface,
audio_port_handle_t *handle);
static int onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration);
static void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration);
private:
// FIXME The 400 is temporarily too high until a leak of writers in media.log is fixed.
static const size_t kLogMemorySize = 400 * 1024;

@ -127,6 +127,7 @@ public:
mHapticIntensity = hapticIntensity;
}
}
sp<os::ExternalVibration> getExternalVibration() const { return mExternalVibration; }
protected:
// for numerous
@ -207,6 +208,16 @@ protected:
bool mHapticPlaybackEnabled = false; // indicates haptic playback enabled or not
// intensity to play haptic data
AudioMixer::haptic_intensity_t mHapticIntensity = AudioMixer::HAPTIC_SCALE_NONE;
class AudioVibrationController : public os::BnExternalVibrationController {
public:
explicit AudioVibrationController(Track* track) : mTrack(track) {}
binder::Status mute(/*out*/ bool *ret) override;
binder::Status unmute(/*out*/ bool *ret) override;
private:
Track* const mTrack;
};
sp<AudioVibrationController> mAudioVibrationController;
sp<os::ExternalVibration> mExternalVibration;
private:
// The following fields are only for fast tracks, and should be in a subclass

@ -2358,15 +2358,23 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING;
}
// Disable all haptic playback for all other active tracks when haptic playback is supported
// and the track contains haptic channels. Enable haptic playback for current track.
// TODO: Request actual haptic playback status from vibrator service
if ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
&& mHapticChannelMask != AUDIO_CHANNEL_NONE) {
for (auto &t : mActiveTracks) {
t->setHapticPlaybackEnabled(false);
// Unlock due to VibratorService will lock for this call and will
// call Tracks.mute/unmute which also require thread's lock.
mLock.unlock();
const int intensity = AudioFlinger::onExternalVibrationStart(
track->getExternalVibration());
mLock.lock();
// Haptic playback should be enabled by vibrator service.
if (track->getHapticPlaybackEnabled()) {
// Disable haptic playback of all active track to ensure only
// one track playing haptic if current track should play haptic.
for (const auto &t : mActiveTracks) {
t->setHapticPlaybackEnabled(false);
}
}
track->setHapticPlaybackEnabled(true);
track->setHapticIntensity(intensity);
}
track->mResetDone = false;
@ -3760,7 +3768,6 @@ bool AudioFlinger::PlaybackThread::threadLoop()
// removeTracks_l() must be called with ThreadBase::mLock held
void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tracksToRemove)
{
bool enabledHapticTracksRemoved = false;
for (const auto& track : tracksToRemove) {
mActiveTracks.remove(track);
ALOGV("%s(%d): removing track on session %d", __func__, track->id(), track->sessionId());
@ -3782,17 +3789,13 @@ void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tra
// remove from our tracks vector
removeTrack_l(track);
}
enabledHapticTracksRemoved |= track->getHapticPlaybackEnabled();
}
// If the thread supports haptic playback and the track playing haptic data was removed,
// enable haptic playback on the first active track that contains haptic channels.
// TODO: Query vibrator service to know which track should enable haptic playback.
if (enabledHapticTracksRemoved && mHapticChannelMask != AUDIO_CHANNEL_NONE) {
for (auto &t : mActiveTracks) {
if (t->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) {
t->setHapticPlaybackEnabled(true);
break;
}
if ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
&& mHapticChannelCount > 0) {
mLock.unlock();
// Unlock due to VibratorService will lock for this call and will
// call Tracks.mute/unmute which also require thread's lock.
AudioFlinger::onExternalVibrationStop(track->getExternalVibration());
mLock.lock();
}
}
}

@ -451,6 +451,12 @@ AudioFlinger::PlaybackThread::Track::Track(
mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
+ "_" + std::to_string(mId));
#endif
if (channelMask & AUDIO_CHANNEL_HAPTIC_ALL) {
mAudioVibrationController = new AudioVibrationController(this);
mExternalVibration = new os::ExternalVibration(
mUid, "" /* pkg */, mAttr, mAudioVibrationController);
}
}
AudioFlinger::PlaybackThread::Track::~Track()
@ -1336,6 +1342,40 @@ void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo(
mServerLatencyMs.store(latencyMs);
}
binder::Status AudioFlinger::PlaybackThread::Track::AudioVibrationController::mute(
/*out*/ bool *ret) {
*ret = false;
sp<ThreadBase> thread = mTrack->mThread.promote();
if (thread != 0) {
// Lock for updating mHapticPlaybackEnabled.
Mutex::Autolock _l(thread->mLock);
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
if ((mTrack->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
&& playbackThread->mHapticChannelCount > 0) {
mTrack->setHapticPlaybackEnabled(false);
*ret = true;
}
}
return binder::Status::ok();
}
binder::Status AudioFlinger::PlaybackThread::Track::AudioVibrationController::unmute(
/*out*/ bool *ret) {
*ret = false;
sp<ThreadBase> thread = mTrack->mThread.promote();
if (thread != 0) {
// Lock for updating mHapticPlaybackEnabled.
Mutex::Autolock _l(thread->mLock);
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
if ((mTrack->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
&& playbackThread->mHapticChannelCount > 0) {
mTrack->setHapticPlaybackEnabled(true);
*ret = true;
}
}
return binder::Status::ok();
}
// ----------------------------------------------------------------------------
#undef LOG_TAG
#define LOG_TAG "AF::OutputTrack"

Loading…
Cancel
Save