diff options
author | Ricardo Cerqueira <cyanogenmod@cerqueira.org> | 2013-01-09 12:42:17 -0800 |
---|---|---|
committer | Gerrit Code Review <gerrit@review.cyanogenmod.com> | 2013-01-09 12:42:17 -0800 |
commit | 87e95973043c3d85774972447425b182d535bbaa (patch) | |
tree | f6d47fca300f75797d68ab3ed533049be8884dc5 | |
parent | 6dcc59e51c11819d668aee09a3265c3cd2717791 (diff) | |
parent | ceb8b69d4a71a32375a8a957d087621638dec50b (diff) | |
download | android_frameworks_base-87e95973043c3d85774972447425b182d535bbaa.tar.gz android_frameworks_base-87e95973043c3d85774972447425b182d535bbaa.tar.bz2 android_frameworks_base-87e95973043c3d85774972447425b182d535bbaa.zip |
Merge "ST_ERICSSON: support for latency" into ics
-rw-r--r-- | include/media/AudioParameter.h | 3 | ||||
-rw-r--r-- | include/media/AudioSystem.h | 19 | ||||
-rw-r--r-- | include/media/AudioTrack.h | 12 | ||||
-rw-r--r-- | include/media/MediaPlayerInterface.h | 8 | ||||
-rw-r--r-- | include/media/stagefright/AudioPlayer.h | 4 | ||||
-rw-r--r-- | media/libmedia/AudioParameter.cpp | 3 | ||||
-rw-r--r-- | media/libmedia/AudioSystem.cpp | 48 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 32 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 46 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 16 | ||||
-rw-r--r-- | media/libstagefright/AudioPlayer.cpp | 27 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 13 |
12 files changed, 229 insertions, 2 deletions
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h index 79d5d82ddb8..7c9536e2c82 100644 --- a/include/media/AudioParameter.h +++ b/include/media/AudioParameter.h @@ -46,6 +46,9 @@ public: static const char *keyChannels; static const char *keyFrameCount; static const char *keyInputSource; +#ifdef STE_HARDWARE + static const char *keyLatency; +#endif String8 toString(); diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index ff401f7ad94..89825257edd 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -31,6 +31,9 @@ namespace android { typedef void (*audio_error_callback)(status_t err); +#ifdef STE_HARDWARE +typedef void (*latency_update_callback)(void *cookie, audio_io_handle_t output, uint32_t latency); +#endif class IAudioPolicyService; class String8; @@ -110,6 +113,10 @@ public: static int newAudioSessionId(); static void acquireAudioSessionId(int audioSession); static void releaseAudioSessionId(int audioSession); +#ifdef STE_HARDWARE + static int registerLatencyNotificationClient(latency_update_callback cb, void *cookie); + static void unregisterLatencyNotificationClient(int clientId); +#endif // types of io configuration change events received with ioConfigChanged() enum io_config_event { @@ -239,6 +246,13 @@ private: virtual void binderDied(const wp<IBinder>& who); }; +#ifdef STE_HARDWARE + struct NotificationClient : public RefBase { + latency_update_callback mCb; + void * mCookie; + }; +#endif + static sp<AudioFlingerClient> gAudioFlingerClient; static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient; friend class AudioFlingerClient; @@ -261,6 +275,11 @@ private: // list of output descriptors containing cached parameters // (sampling rate, framecount, channel count...) static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs; +#ifdef STE_HARDWARE + static Mutex gLatencyLock; + static int gNextUniqueLatencyId; + static DefaultKeyedVector<int, sp<AudioSystem::NotificationClient> > gLatencyNotificationClients; +#endif }; }; // namespace android diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index f518198885b..1208adad182 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -55,7 +55,12 @@ public: EVENT_LOOP_END = 2, // Sample loop end was reached; playback restarted from loop start if loop count was not 0. EVENT_MARKER = 3, // Playback head is at the specified marker position (See setMarkerPosition()). EVENT_NEW_POS = 4, // Playback head is at a new position (See setPositionUpdatePeriod()). +#ifdef STE_HARDWARE + EVENT_BUFFER_END = 5, // Playback head is at the end of the buffer. + EVENT_LATENCY_CHANGED = 6 // Audio output has been reconfigured and latency has changed. +#else EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer. +#endif }; /* Create Buffer on the stack and pass it to obtainBuffer() @@ -480,6 +485,10 @@ private: status_t setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount); audio_io_handle_t getOutput_l(); status_t restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart); +#ifdef STE_HARDWARE + static void LatencyCallbackWrapper(void *cookie, audio_io_handle_t output, uint32_t latency); + void latencyCallback(audio_io_handle_t output, uint32_t latency); +#endif sp<IAudioTrack> mAudioTrack; sp<IMemory> mCblkMemory; @@ -521,6 +530,9 @@ private: int mAuxEffectId; Mutex mLock; status_t mRestoreStatus; +#ifdef STE_HARDWARE + int mLatencyClientId; +#endif }; diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h index d23d2c44303..9088a869a12 100644 --- a/include/media/MediaPlayerInterface.h +++ b/include/media/MediaPlayerInterface.h @@ -68,6 +68,9 @@ public: // Callback returns the number of bytes actually written to the buffer. typedef size_t (*AudioCallback)( AudioSink *audioSink, void *buffer, size_t size, void *cookie); +#ifdef STE_HARDWARE + typedef void (*LatencyCallback)(uint32_t latency, void *cookie); +#endif virtual ~AudioSink() {} virtual bool ready() const = 0; // audio output is open and ready @@ -88,7 +91,12 @@ public: int format=AUDIO_FORMAT_PCM_16_BIT, int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT, AudioCallback cb = NULL, +#ifdef STE_HARDWARE + void *cookie = NULL, + LatencyCallback latencyCb = NULL) = 0; +#else void *cookie = NULL) = 0; +#endif #ifdef WITH_QCOM_LPA // API to open a routing session for tunneled audio playback diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h index bb05ba3cc03..dd09f187506 100644 --- a/include/media/stagefright/AudioPlayer.h +++ b/include/media/stagefright/AudioPlayer.h @@ -104,6 +104,10 @@ private: MediaPlayerBase::AudioSink *audioSink, void *data, size_t size, void *me); +#ifdef STE_HARDWARE + static void LatencyCallback(uint32_t latency, void *cookie); +#endif + size_t fillBuffer(void *data, size_t size); int64_t getRealTimeUsLocked() const; diff --git a/media/libmedia/AudioParameter.cpp b/media/libmedia/AudioParameter.cpp index 59ccfd00f3c..60046e407f5 100644 --- a/media/libmedia/AudioParameter.cpp +++ b/media/libmedia/AudioParameter.cpp @@ -29,6 +29,9 @@ const char *AudioParameter::keyFormat = "format"; const char *AudioParameter::keyChannels = "channels"; const char *AudioParameter::keyFrameCount = "frame_count"; const char *AudioParameter::keyInputSource = "input_source"; +#ifdef STE_HARDWARE +const char *AudioParameter::keyLatency = "latency"; +#endif AudioParameter::AudioParameter(const String8& keyValuePairs) { diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 98959b85ac2..dc4ad4df9ab 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -45,6 +45,13 @@ int AudioSystem::gPrevInChannelCount = 1; size_t AudioSystem::gInBuffSize = 0; +#ifdef STE_HARDWARE +// Clients for receiving latency update notifications +Mutex AudioSystem::gLatencyLock; +int AudioSystem::gNextUniqueLatencyId = 0; +DefaultKeyedVector<int, sp<AudioSystem::NotificationClient> > AudioSystem::gLatencyNotificationClients(0); +#endif + // establish binder interface to AudioFlinger service const sp<IAudioFlinger>& AudioSystem::get_audio_flinger() { @@ -370,9 +377,32 @@ void AudioSystem::releaseAudioSessionId(int audioSession) { } } +#ifdef STE_HARDWARE +int AudioSystem::registerLatencyNotificationClient(latency_update_callback cb, void *cookie) { + Mutex::Autolock _l(gLatencyLock); + + sp<NotificationClient> notificationClient = new NotificationClient(); + notificationClient->mCb = cb; + notificationClient->mCookie = cookie; + + gNextUniqueLatencyId++; + gLatencyNotificationClients.add(gNextUniqueLatencyId, notificationClient); + return gNextUniqueLatencyId; +} + +void AudioSystem::unregisterLatencyNotificationClient(int clientId) { + Mutex::Autolock _l(gLatencyLock); + gLatencyNotificationClients.removeItem(clientId); +} // --------------------------------------------------------------------------- +#endif void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) { +#ifdef STE_HARDWARE + gLatencyLock.lock(); + AudioSystem::gLatencyNotificationClients.clear(); + gLatencyLock.unlock(); +#endif Mutex::Autolock _l(AudioSystem::gLock); AudioSystem::gAudioFlinger.clear(); @@ -445,9 +475,27 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(int event, int ioHandle, v ioHandle, desc->samplingRate, desc->format, desc->channels, desc->frameCount, desc->latency); OutputDescriptor *outputDesc = gOutputs.valueAt(index); +#ifdef STE_HARDWARE + uint32_t oldLatency = outputDesc->latency; +#endif delete outputDesc; outputDesc = new OutputDescriptor(*desc); gOutputs.replaceValueFor(ioHandle, outputDesc); +#ifdef STE_HARDWARE + if (oldLatency == outputDesc->latency) { + break; + } + uint32_t newLatency = outputDesc->latency; + gLock.unlock(); + gLatencyLock.lock(); + size_t size = gLatencyNotificationClients.size(); + for (size_t i = 0; i < size; i++) { + sp<NotificationClient> client = gLatencyNotificationClients.valueAt(i); + (*client->mCb)(client->mCookie, ioHandle, newLatency); + } + gLatencyLock.unlock(); + gLock.lock(); +#endif } break; case INPUT_OPENED: case INPUT_CLOSED: diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index a9ab9828cdc..938aea8a774 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -78,7 +78,6 @@ status_t AudioTrack::getMinFrameCount( if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) { return NO_INIT; } - // Ensure that buffer depth covers at least audio hardware latency uint32_t minBufCount = afLatency / ((1000 * afFrameCount) / afSampleRate); if (minBufCount < 2) minBufCount = 2; @@ -215,6 +214,9 @@ AudioTrack::~AudioTrack() AudioSystem::releaseAudioSessionId(mSessionId); #endif } +#ifdef STE_HARDWARE + AudioSystem::unregisterLatencyNotificationClient(mLatencyClientId); +#endif } status_t AudioTrack::set( @@ -345,6 +347,10 @@ status_t AudioTrack::set( #endif AudioSystem::acquireAudioSessionId(mSessionId); mRestoreStatus = NO_ERROR; +#ifdef STE_HARDWARE + mLatencyClientId = AudioSystem::registerLatencyNotificationClient( + &AudioTrack::LatencyCallbackWrapper, this); +#endif return NO_ERROR; } @@ -1479,6 +1485,30 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const return NO_ERROR; } +#ifdef STE_HARDWARE +// static +void AudioTrack::LatencyCallbackWrapper(void *cookie, audio_io_handle_t output, uint32_t latency) +{ + static_cast<AudioTrack *>(cookie)->latencyCallback(output, latency); +} + +void AudioTrack::latencyCallback(audio_io_handle_t output, uint32_t latency) +{ + audio_io_handle_t myOutput = getOutput(); + if (output != myOutput) { + return; + } + + uint32_t oldLatency = mLatency; + mLatency = latency + (1000*mCblk->frameCount) / mCblk->sampleRate; + LOGV("new latency for output %d (old latency %d, new latency %d)", output, oldLatency, mLatency); + + if (mCbf != NULL) { + mCbf(EVENT_LATENCY_CHANGED, mUserData, &mLatency); + } +} +#endif + // ========================================================================= AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava) diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 2888888bb5a..17216d024d5 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -321,7 +321,11 @@ status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& a mStreamType, mLeftVolume, mRightVolume); result.append(buffer); snprintf(buffer, 255, " msec per frame(%f), latency (%d)\n", +#ifdef STE_HARDWARE + mMsecsPerFrame, mLatency); +#else mMsecsPerFrame, (mTrack != 0) ? mTrack->latency() : -1); +#endif result.append(buffer); snprintf(buffer, 255, " aux effect id(%d), send level (%f)\n", mAuxEffectId, mSendLevel); @@ -1269,6 +1273,9 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId) mStreamType = AUDIO_STREAM_MUSIC; mLeftVolume = 1.0; mRightVolume = 1.0; +#ifdef STE_HARDWARE + mLatency = 0; +#endif mMsecsPerFrame = 0; mAuxEffectId = 0; mSendLevel = 0.0; @@ -1330,8 +1337,12 @@ ssize_t MediaPlayerService::AudioOutput::frameSize() const uint32_t MediaPlayerService::AudioOutput::latency () const { +#ifdef STE_HARDWARE + return mLatency; +#else if (mTrack == 0) return 0; return mTrack->latency(); +#endif } float MediaPlayerService::AudioOutput::msecsPerFrame() const @@ -1380,10 +1391,17 @@ status_t MediaPlayerService::AudioOutput::openSession( status_t MediaPlayerService::AudioOutput::open( uint32_t sampleRate, int channelCount, int format, int bufferCount, +#ifdef STE_HARDWARE + AudioCallback cb, void *cookie, LatencyCallback latencyCb) +#else AudioCallback cb, void *cookie) +#endif { mCallback = cb; mCallbackCookie = cookie; +#ifdef STE_HARDWARE + mLatencyCallback = latencyCb; +#endif // Check argument "bufferCount" against the mininum buffer count if (bufferCount < mMinBufferCount) { @@ -1443,6 +1461,9 @@ status_t MediaPlayerService::AudioOutput::open( t->setVolume(mLeftVolume, mRightVolume); mMsecsPerFrame = 1.e3 / (float) sampleRate; +#ifdef STE_HARDWARE + mLatency = t->latency(); +#endif mTrack = t; t->setAuxEffectSendLevel(mSendLevel); @@ -1494,10 +1515,15 @@ void MediaPlayerService::AudioOutput::pause() void MediaPlayerService::AudioOutput::close() { LOGV("close"); +#ifdef STE_HARDWARE + delete mTrack; + mTrack = 0; +#else if(mTrack != NULL) { delete mTrack; mTrack = 0; } +#endif } #ifdef WITH_QCOM_LPA void MediaPlayerService::AudioOutput::closeSession() @@ -1568,10 +1594,13 @@ status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId) void MediaPlayerService::AudioOutput::CallbackWrapper( int event, void *cookie, void *info) { //LOGV("callbackwrapper"); +#ifdef STE_HARDWARE + if (event == AudioTrack::EVENT_MORE_DATA) { +#else if (event != AudioTrack::EVENT_MORE_DATA) { return; } - +#endif AudioOutput *me = (AudioOutput *)cookie; AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; @@ -1587,6 +1616,17 @@ void MediaPlayerService::AudioOutput::CallbackWrapper( } buffer->size = actualSize; +#ifdef STE_HARDWARE + } else if (event == AudioTrack::EVENT_LATENCY_CHANGED) { + AudioOutput *me = (AudioOutput *)cookie; + + uint32_t *newLatency = (uint32_t *)info; + me->mLatency = *newLatency; + if (me->mLatencyCallback != NULL) { + (*me->mLatencyCallback)(*newLatency, me->mCallbackCookie); + } + } +#endif } int MediaPlayerService::AudioOutput::getSessionId() @@ -1687,7 +1727,11 @@ bool CallbackThread::threadLoop() { status_t MediaPlayerService::AudioCache::open( uint32_t sampleRate, int channelCount, int format, int bufferCount, +#ifdef STE_HARDWARE + AudioCallback cb, void *cookie, LatencyCallback latencyCb) +#else AudioCallback cb, void *cookie) +#endif { LOGV("open(%u, %d, %d, %d)", sampleRate, channelCount, format, bufferCount); if (mHeap->getHeapID() < 0) { diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 24a8d09b3c5..4bde518557c 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -84,7 +84,12 @@ class MediaPlayerService : public BnMediaPlayerService virtual status_t open( uint32_t sampleRate, int channelCount, int format, int bufferCount, +#ifdef STE_HARDWARE + AudioCallback cb, void *cookie, + LatencyCallback latencyCb = NULL); +#else AudioCallback cb, void *cookie); +#endif #ifdef WITH_QCOM_LPA virtual status_t openSession( int format, int sessionId, uint32_t sampleRate, int channels); @@ -124,10 +129,16 @@ class MediaPlayerService : public BnMediaPlayerService #endif AudioCallback mCallback; void * mCallbackCookie; +#ifdef STE_HARDWARE + LatencyCallback mLatencyCallback; +#endif int mStreamType; float mLeftVolume; float mRightVolume; float mMsecsPerFrame; +#ifdef STE_HARDWARE + uint32_t mLatency; +#endif int mSessionId; float mSendLevel; int mAuxEffectId; @@ -156,7 +167,12 @@ class MediaPlayerService : public BnMediaPlayerService virtual status_t open( uint32_t sampleRate, int channelCount, int format, int bufferCount = 1, +#ifdef STE_HARDWARE + AudioCallback cb = NULL, void *cookie = NULL, + LatencyCallback latencyCb = NULL); +#else AudioCallback cb = NULL, void *cookie = NULL); +#endif virtual void start(); virtual ssize_t write(const void* buffer, size_t size); diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index ea04288f888..290e562b824 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -124,7 +124,12 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) { status_t err = mAudioSink->open( mSampleRate, numChannels, AUDIO_FORMAT_PCM_16_BIT, DEFAULT_AUDIOSINK_BUFFERCOUNT, +#ifdef STE_HARDWARE + &AudioPlayer::AudioSinkCallback, this, + &AudioPlayer::LatencyCallback); +#else &AudioPlayer::AudioSinkCallback, this); +#endif if (err != OK) { if (mFirstBuffer != NULL) { mFirstBuffer->release(); @@ -275,6 +280,16 @@ void AudioPlayer::AudioCallback(int event, void *user, void *info) { static_cast<AudioPlayer *>(user)->AudioCallback(event, info); } +#ifdef STE_HARDWARE +// static +void AudioPlayer::LatencyCallback(uint32_t latency, void *cookie) { + AudioPlayer *me = (AudioPlayer *)cookie; + int64_t oldLatency = me->mLatencyUs; + me->mLatencyUs = (int64_t)latency * 1000; + LOGI("Audio output latency updated from %lldus to %lldus", oldLatency, me->mLatencyUs); +} +#endif + bool AudioPlayer::isSeeking() { Mutex::Autolock autoLock(mLock); return mSeeking; @@ -298,14 +313,26 @@ size_t AudioPlayer::AudioSinkCallback( } void AudioPlayer::AudioCallback(int event, void *info) { +#ifdef STE_HARDWARE + if (event == AudioTrack::EVENT_MORE_DATA) { +#else if (event != AudioTrack::EVENT_MORE_DATA) { return; } +#endif AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info; size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size); buffer->size = numBytesWritten; +#ifdef STE_HARDWARE + } else if (event == AudioTrack::EVENT_LATENCY_CHANGED) { + uint32_t *newLatency = (uint32_t *)info; + int64_t oldLatency = mLatencyUs; + mLatencyUs = (int64_t)*newLatency * 1000; + LOGI("Audio output latency updated from %lldus to %lldus", oldLatency, mLatencyUs); + } +#endif } uint32_t AudioPlayer::getNumFramesPendingPlayout() const { diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 6bd7245cc42..e0e17f6194a 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -2748,6 +2748,9 @@ void AudioFlinger::MixerThread::deleteTrackName_l(int name) bool AudioFlinger::MixerThread::checkForNewParameters_l() { bool reconfig = false; +#ifdef STE_HARDWARE + bool updateLatency = false; +#endif while (!mNewParameters.isEmpty()) { status_t status = NO_ERROR; @@ -2811,6 +2814,11 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l() mEffectChains[i]->setDevice_l(mDevice); } } +#ifdef STE_HARDWARE + if (param.getInt(String8(AudioParameter::keyLatency), value) == NO_ERROR) { + updateLatency = true; +#endif + } if (status == NO_ERROR) { status = mOutput->stream->common.set_parameters(&mOutput->stream->common, @@ -2837,6 +2845,11 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l() } sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED); } +#ifdef STE_HARDWARE + if (status == NO_ERROR && updateLatency) { + sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED); + } +#endif } mNewParameters.removeAt(0); |