summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNaveen Agarwal <naveen.agarwal@stericsson.com>2012-04-05 21:06:59 +0000
committerMathieu J. Poirier <mathieu.poirier@linaro.org>2012-04-10 09:14:22 -0600
commite8cfc22c08e32b463186362ed40abb4d34eedca8 (patch)
tree0cebf07b3f22b3589121e67df01bc927ff5b06a7
parent151ce20c17e1a097a2edf5b467650941a1cc6287 (diff)
downloadbase-e8cfc22c08e32b463186362ed40abb4d34eedca8.tar.gz
Add support for update of audio output latency on Snowball
Adds mechanisms enabling AudioPlayer to receive updated latency values for the audio output. The possibility to update the latency value is needed because the latency values for some devices (e.g., A2DP devices) are not known until they have been opened. Latency value updates will also occur when output device is exchanged on-the-fly during playback (e.g., audio output is moved from headset to A2DP device). This patch modifies the MediaPlayerService::open() function declaration which is part of an Android internal interface. Although, this is a backward compatible change since only a default parameter is added. ST-Ericsson ID: 372587 ST-Ericsson FOSS-OUT ID: STETL-FOSS-OUT-12221 Introduce backward compatible changes to exposed interfaces Change-Id: I2edf117bf22305232dec67a27e9a00002c01e197 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/41850 Reviewed-by: Stefan EKENBERG <stefan.ekenberg@stericsson.com> Reviewed-by: Axel FAGERSTEDT <axel.fagerstedt@stericsson.com> Tested-by: Naveen AGARWAL <naveen.agarwal@stericsson.com> Reviewed-by: Naveen AGARWAL <naveen.agarwal@stericsson.com> Reviewed-by: Devinder THAKUR <devinder.thakur@stericsson.com> Committed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
-rw-r--r--include/media/AudioParameter.h1
-rw-r--r--include/media/AudioSystem.h13
-rw-r--r--include/media/AudioTrack.h7
-rw-r--r--include/media/MediaPlayerInterface.h4
-rw-r--r--include/media/stagefright/AudioPlayer.h1
-rw-r--r--media/libmedia/AudioParameter.cpp1
-rw-r--r--media/libmedia/AudioSystem.cpp39
-rw-r--r--media/libmedia/AudioTrack.cpp25
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp39
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h7
-rw-r--r--media/libstagefright/AudioPlayer.cpp22
-rw-r--r--services/audioflinger/AudioFlinger.cpp7
12 files changed, 140 insertions, 26 deletions
diff --git a/include/media/AudioParameter.h b/include/media/AudioParameter.h
index 79d5d82ddb8a..86b0e13dd2cf 100644
--- a/include/media/AudioParameter.h
+++ b/include/media/AudioParameter.h
@@ -46,6 +46,7 @@ public:
static const char *keyChannels;
static const char *keyFrameCount;
static const char *keyInputSource;
+ static const char *keyLatency;
String8 toString();
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 95d539efec8c..2072dced5cac 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -30,7 +30,7 @@
namespace android {
typedef void (*audio_error_callback)(status_t err);
-
+typedef void (*latency_update_callback)(void *cookie, audio_io_handle_t output, uint32_t latency);
class IAudioPolicyService;
class String8;
@@ -110,6 +110,9 @@ public:
static int newAudioSessionId();
static void acquireAudioSessionId(int audioSession);
static void releaseAudioSessionId(int audioSession);
+ static int registerLatencyNotificationClient(latency_update_callback cb, void *cookie);
+ static void unregisterLatencyNotificationClient(int clientId);
+
// types of io configuration change events received with ioConfigChanged()
enum io_config_event {
OUTPUT_OPENED,
@@ -221,6 +224,11 @@ private:
virtual void binderDied(const wp<IBinder>& who);
};
+ struct NotificationClient : public RefBase {
+ latency_update_callback mCb;
+ void * mCookie;
+ };
+
static sp<AudioFlingerClient> gAudioFlingerClient;
static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient;
friend class AudioFlingerClient;
@@ -243,6 +251,9 @@ private:
// list of output descriptors containing cached parameters
// (sampling rate, framecount, channel count...)
static DefaultKeyedVector<audio_io_handle_t, OutputDescriptor *> gOutputs;
+ static Mutex gLatencyLock;
+ static int gNextUniqueLatencyId;
+ static DefaultKeyedVector<int, sp<AudioSystem::NotificationClient> > gLatencyNotificationClients;
};
}; // namespace android
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index f6f2537cae29..d334094b781e 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -55,7 +55,8 @@ 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()).
- EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer.
+ 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.
};
/* Create Buffer on the stack and pass it to obtainBuffer()
@@ -449,6 +450,9 @@ 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);
+ static void LatencyCallbackWrapper(void *cookie, audio_io_handle_t output, uint32_t latency);
+ void latencyCallback(audio_io_handle_t output, uint32_t latency);
+
sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory;
sp<AudioTrackThread> mAudioTrackThread;
@@ -486,6 +490,7 @@ private:
int mAuxEffectId;
Mutex mLock;
status_t mRestoreStatus;
+ int mLatencyClientId;
};
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 80f43a342a55..256a2bcd9624 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -68,6 +68,7 @@ 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);
+ typedef void (*LatencyCallback)(uint32_t latency, void *cookie);
virtual ~AudioSink() {}
virtual bool ready() const = 0; // audio output is open and ready
@@ -88,7 +89,8 @@ public:
int format=AUDIO_FORMAT_PCM_16_BIT,
int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
AudioCallback cb = NULL,
- void *cookie = NULL) = 0;
+ void *cookie = NULL,
+ LatencyCallback latencyCb = NULL) = 0;
virtual void start() = 0;
virtual ssize_t write(const void* buffer, size_t size) = 0;
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index ae5937d469aa..c878bee9883c 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -101,6 +101,7 @@ private:
static size_t AudioSinkCallback(
MediaPlayerBase::AudioSink *audioSink,
void *data, size_t size, void *me);
+ static void LatencyCallback(uint32_t latency, void *cookie);
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 59ccfd00f3cb..8d6b71be28f4 100644
--- a/media/libmedia/AudioParameter.cpp
+++ b/media/libmedia/AudioParameter.cpp
@@ -29,6 +29,7 @@ const char *AudioParameter::keyFormat = "format";
const char *AudioParameter::keyChannels = "channels";
const char *AudioParameter::keyFrameCount = "frame_count";
const char *AudioParameter::keyInputSource = "input_source";
+const char *AudioParameter::keyLatency = "latency";
AudioParameter::AudioParameter(const String8& keyValuePairs)
{
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 4ec0483850b0..e300af24f412 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -44,6 +44,11 @@ int AudioSystem::gPrevInFormat = AUDIO_FORMAT_PCM_16_BIT;
int AudioSystem::gPrevInChannelCount = 1;
size_t AudioSystem::gInBuffSize = 0;
+// Clients for receiving latency update notifications
+Mutex AudioSystem::gLatencyLock;
+int AudioSystem::gNextUniqueLatencyId = 0;
+DefaultKeyedVector<int, sp<AudioSystem::NotificationClient> > AudioSystem::gLatencyNotificationClients(0);
+
// establish binder interface to AudioFlinger service
const sp<IAudioFlinger>& AudioSystem::get_audio_flinger()
{
@@ -369,9 +374,29 @@ void AudioSystem::releaseAudioSessionId(int audioSession) {
}
}
+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);
+}
// ---------------------------------------------------------------------------
void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {
+ gLatencyLock.lock();
+ AudioSystem::gLatencyNotificationClients.clear();
+ gLatencyLock.unlock();
+
Mutex::Autolock _l(AudioSystem::gLock);
AudioSystem::gAudioFlinger.clear();
@@ -444,9 +469,23 @@ 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);
+ uint32_t oldLatency = outputDesc->latency;
delete outputDesc;
outputDesc = new OutputDescriptor(*desc);
gOutputs.replaceValueFor(ioHandle, outputDesc);
+ 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();
} break;
case INPUT_OPENED:
case INPUT_CLOSED:
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 8ebb6521382b..1d2a479e3820 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -136,6 +136,7 @@ AudioTrack::~AudioTrack()
IPCThreadState::self()->flushCommands();
AudioSystem::releaseAudioSessionId(mSessionId);
}
+ AudioSystem::unregisterLatencyNotificationClient(mLatencyClientId);
}
status_t AudioTrack::set(
@@ -263,6 +264,8 @@ status_t AudioTrack::set(
mFlags = flags;
AudioSystem::acquireAudioSessionId(mSessionId);
mRestoreStatus = NO_ERROR;
+ mLatencyClientId = AudioSystem::registerLatencyNotificationClient(
+ &AudioTrack::LatencyCallbackWrapper, this);
return NO_ERROR;
}
@@ -1281,6 +1284,28 @@ status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
return NO_ERROR;
}
+// 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);
+ }
+}
+
// =========================================================================
AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava)
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 38f96dc77d6f..c8683b801ea6 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1340,10 +1340,11 @@ status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position)
status_t MediaPlayerService::AudioOutput::open(
uint32_t sampleRate, int channelCount, int format, int bufferCount,
- AudioCallback cb, void *cookie)
+ AudioCallback cb, void *cookie, LatencyCallback latencyCb)
{
mCallback = cb;
mCallbackCookie = cookie;
+ mLatencyCallback = latencyCb;
// Check argument "bufferCount" against the mininum buffer count
if (bufferCount < mMinBufferCount) {
@@ -1493,25 +1494,31 @@ status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
void MediaPlayerService::AudioOutput::CallbackWrapper(
int event, void *cookie, void *info) {
//LOGV("callbackwrapper");
- if (event != AudioTrack::EVENT_MORE_DATA) {
- return;
- }
+ if (event == AudioTrack::EVENT_MORE_DATA) {
+ AudioOutput *me = (AudioOutput *)cookie;
+ AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+
+ size_t actualSize = (*me->mCallback)(
+ me, buffer->raw, buffer->size, me->mCallbackCookie);
- AudioOutput *me = (AudioOutput *)cookie;
- AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
+ if (actualSize == 0 && buffer->size > 0) {
+ // We've reached EOS but the audio track is not stopped yet,
+ // keep playing silence.
- size_t actualSize = (*me->mCallback)(
- me, buffer->raw, buffer->size, me->mCallbackCookie);
+ memset(buffer->raw, 0, buffer->size);
+ actualSize = buffer->size;
+ }
- if (actualSize == 0 && buffer->size > 0) {
- // We've reached EOS but the audio track is not stopped yet,
- // keep playing silence.
+ buffer->size = actualSize;
+ } else if (event == AudioTrack::EVENT_LATENCY_CHANGED) {
+ AudioOutput *me = (AudioOutput *)cookie;
- memset(buffer->raw, 0, buffer->size);
- actualSize = buffer->size;
+ uint32_t *newLatency = (uint32_t *)info;
+ me->mLatency = *newLatency;
+ if (me->mLatencyCallback != NULL) {
+ (*me->mLatencyCallback)(*newLatency, me->mCallbackCookie);
+ }
}
-
- buffer->size = actualSize;
}
int MediaPlayerService::AudioOutput::getSessionId()
@@ -1612,7 +1619,7 @@ bool CallbackThread::threadLoop() {
status_t MediaPlayerService::AudioCache::open(
uint32_t sampleRate, int channelCount, int format, int bufferCount,
- AudioCallback cb, void *cookie)
+ AudioCallback cb, void *cookie, LatencyCallback latencyCb)
{
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 a820114fd9a2..9f6cd14a33fa 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -84,7 +84,8 @@ class MediaPlayerService : public BnMediaPlayerService
virtual status_t open(
uint32_t sampleRate, int channelCount,
int format, int bufferCount,
- AudioCallback cb, void *cookie);
+ AudioCallback cb, void *cookie,
+ LatencyCallback latencyCb = NULL);
virtual void start();
virtual ssize_t write(const void* buffer, size_t size);
virtual void stop();
@@ -107,6 +108,7 @@ class MediaPlayerService : public BnMediaPlayerService
AudioTrack* mTrack;
AudioCallback mCallback;
void * mCallbackCookie;
+ LatencyCallback mLatencyCallback;
int mStreamType;
float mLeftVolume;
float mRightVolume;
@@ -140,7 +142,8 @@ class MediaPlayerService : public BnMediaPlayerService
virtual status_t open(
uint32_t sampleRate, int channelCount, int format,
int bufferCount = 1,
- AudioCallback cb = NULL, void *cookie = NULL);
+ AudioCallback cb = NULL, void *cookie = NULL,
+ LatencyCallback latencyCb = NULL);
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 2581a62eca44..ecee9a750e30 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -118,7 +118,8 @@ status_t AudioPlayer::start(bool sourceAlreadyStarted) {
status_t err = mAudioSink->open(
mSampleRate, numChannels, AUDIO_FORMAT_PCM_16_BIT,
DEFAULT_AUDIOSINK_BUFFERCOUNT,
- &AudioPlayer::AudioSinkCallback, this);
+ &AudioPlayer::AudioSinkCallback, this,
+ &AudioPlayer::LatencyCallback);
if (err != OK) {
if (mFirstBuffer != NULL) {
mFirstBuffer->release();
@@ -255,6 +256,14 @@ void AudioPlayer::AudioCallback(int event, void *user, void *info) {
static_cast<AudioPlayer *>(user)->AudioCallback(event, info);
}
+// 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);
+}
+
bool AudioPlayer::isSeeking() {
Mutex::Autolock autoLock(mLock);
return mSeeking;
@@ -278,14 +287,17 @@ size_t AudioPlayer::AudioSinkCallback(
}
void AudioPlayer::AudioCallback(int event, void *info) {
- if (event != AudioTrack::EVENT_MORE_DATA) {
- return;
- }
-
+ if (event == AudioTrack::EVENT_MORE_DATA) {
AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
size_t numBytesWritten = fillBuffer(buffer->raw, buffer->size);
buffer->size = numBytesWritten;
+ } 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);
+ }
}
uint32_t AudioPlayer::getNumFramesPendingPlayout() const {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 93a73fb59cc2..461474664d6d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -2324,6 +2324,7 @@ void AudioFlinger::MixerThread::deleteTrackName_l(int name)
bool AudioFlinger::MixerThread::checkForNewParameters_l()
{
bool reconfig = false;
+ bool updateLatency = false;
while (!mNewParameters.isEmpty()) {
status_t status = NO_ERROR;
@@ -2387,6 +2388,9 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
mEffectChains[i]->setDevice_l(mDevice);
}
}
+ if (param.getInt(String8(AudioParameter::keyLatency), value) == NO_ERROR) {
+ updateLatency = true;
+ }
if (status == NO_ERROR) {
status = mOutput->stream->common.set_parameters(&mOutput->stream->common,
@@ -2413,6 +2417,9 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
}
sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
}
+ if (status == NO_ERROR && updateLatency) {
+ sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
+ }
}
mNewParameters.removeAt(0);