Merge "Audio V4: Send volume and duplicated track attr in update metadata" into pi-dev

gugelfrei
TreeHugger Robot 6 years ago committed by Android (Google) Code Review
commit 9fc25229e0

@ -19,8 +19,11 @@
#define ANDROID_AUDIO_FLINGER_H
#include "Configuration.h"
#include <atomic>
#include <mutex>
#include <deque>
#include <map>
#include <vector>
#include <stdint.h>
#include <sys/types.h>
#include <limits.h>

@ -93,6 +93,23 @@ public:
const sp<media::VolumeShaper::Operation>& operation);
sp<media::VolumeShaper::State> getVolumeShaperState(int id);
sp<media::VolumeHandler> getVolumeHandler() { return mVolumeHandler; }
/** Set the computed normalized final volume of the track.
* !masterMute * masterVolume * streamVolume * averageLRVolume */
void setFinalVolume(float volume);
float getFinalVolume() const { return mFinalVolume; }
/** @return true if the track has changed (metadata or volume) since
* the last time this function was called,
* true if this function was never called since the track creation,
* false otherwise.
* Thread safe.
*/
bool readAndClearHasChanged() { return !mChangeNotified.test_and_set(); }
using SourceMetadatas = std::vector<playback_track_metadata_t>;
using MetadataInserter = std::back_insert_iterator<SourceMetadatas>;
/** Copy the track metadata in the provided iterator. Thread safe. */
virtual void copyMetadataTo(MetadataInserter& backInserter) const;
protected:
// for numerous
@ -133,6 +150,8 @@ protected:
bool presentationComplete(int64_t framesWritten, size_t audioHalFrames);
void signalClientFlag(int32_t flag);
/** Set that a metadata has changed and needs to be notified to backend. Thread safe. */
void setMetadataHasChanged() { mChangeNotified.clear(); }
public:
void triggerEvents(AudioSystem::sync_event_t type);
virtual void invalidate();
@ -182,10 +201,13 @@ private:
volatile float mCachedVolume; // combined master volume and stream type volume;
// 'volatile' means accessed without lock or
// barrier, but is read/written atomically
float mFinalVolume; // combine master volume, stream type volume and track volume
sp<AudioTrackServerProxy> mAudioTrackServerProxy;
bool mResumeToStopping; // track was paused in stopping state.
bool mFlushHwPending; // track requests for thread flush
audio_output_flags_t mFlags;
// If the last track change was notified to the client with readAndClearHasChanged
std::atomic_flag mChangeNotified = ATOMIC_FLAG_INIT;
}; // end of Track
@ -216,8 +238,11 @@ public:
bool isActive() const { return mActive; }
const wp<ThreadBase>& thread() const { return mThread; }
private:
void copyMetadataTo(MetadataInserter& backInserter) const override;
/** Set the metadatas of the upstream tracks. Thread safe. */
void setMetadatas(const SourceMetadatas& metadatas);
private:
status_t obtainBuffer(AudioBufferProvider::Buffer* buffer,
uint32_t waitTimeMs);
void clearBufferQueue();
@ -232,6 +257,20 @@ private:
bool mActive;
DuplicatingThread* const mSourceThread; // for waitTimeMs() in write()
sp<AudioTrackClientProxy> mClientProxy;
/** Attributes of the source tracks.
*
* This member must be accessed with mTrackMetadatasMutex taken.
* There is one writer (duplicating thread) and one reader (downstream mixer).
*
* That means that the duplicating thread can block the downstream mixer
* thread and vice versa for the time of the copy.
* If this becomes an issue, the metadata could be stored in an atomic raw pointer,
* and a exchange with nullptr and delete can be used.
* Alternatively a read-copy-update might be implemented.
*/
SourceMetadatas mTrackMetadatas;
/** Protects mTrackMetadatas against concurrent access. */
mutable std::mutex mTrackMetadatasMutex;
}; // end of OutputTrack
// playback track, used by PatchPanel

@ -2623,27 +2623,33 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
void AudioFlinger::PlaybackThread::updateMetadata_l()
{
// TODO: add volume support
if (mOutput == nullptr || mOutput->stream == nullptr ||
!mActiveTracks.readAndClearHasChanged()) {
return;
if (mOutput == nullptr || mOutput->stream == nullptr ) {
return; // That should not happen
}
bool hasChanged = mActiveTracks.readAndClearHasChanged();
for (const sp<Track> &track : mActiveTracks) {
// Do not short-circuit as all hasChanged states must be reset
// as all the metadata are going to be sent
hasChanged |= track->readAndClearHasChanged();
}
if (!hasChanged) {
return; // nothing to do
}
StreamOutHalInterface::SourceMetadata metadata;
auto backInserter = std::back_inserter(metadata.tracks);
for (const sp<Track> &track : mActiveTracks) {
// No track is invalid as this is called after prepareTrack_l in the same critical section
if (track->isOutputTrack()) {
// TODO: OutputTrack (used for duplication) are currently not supported
continue;
}
metadata.tracks.push_back({
.usage = track->attributes().usage,
.content_type = track->attributes().content_type,
.gain = 1,
});
track->copyMetadataTo(backInserter);
}
mOutput->stream->updateSourceMetadata(metadata);
sendMetadataToBackend_l(metadata);
}
void AudioFlinger::PlaybackThread::sendMetadataToBackend_l(
const StreamOutHalInterface::SourceMetadata& metadata)
{
mOutput->stream->updateSourceMetadata(metadata);
};
status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames)
{
if (halFrames == NULL || dspFrames == NULL) {
@ -4381,13 +4387,19 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
didModify = true;
// no acknowledgement required for newly active tracks
}
sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
// cache the combined master volume and stream type volume for fast mixer; this
// lacks any synchronization or barrier so VolumeProvider may read a stale value
const float vh = track->getVolumeHandler()->getVolume(
track->mAudioTrackServerProxy->framesReleased()).first;
track->mCachedVolume = masterVolume
proxy->framesReleased()).first;
float volume = masterVolume
* mStreamTypes[track->streamType()].volume
* vh;
track->mCachedVolume = masterVolume;
gain_minifloat_packed_t vlr = proxy->getVolumeLR();
float vlf = volume * float_from_gain(gain_minifloat_unpack_left(vlr));
float vrf = volume * float_from_gain(gain_minifloat_unpack_right(vlr));
track->setFinalVolume((vlf + vrf) / 2.f);
++fastTracks;
} else {
// was it previously active?
@ -4564,6 +4576,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
vaf = v * sendLevel * (1. / MAX_GAIN_INT);
}
track->setFinalVolume((vrf + vlf) / 2.f);
// Delegate volume control to effect in track effect chain if needed
if (chain != 0 && chain->setVolume_l(&vl, &vr)) {
// Do not ramp volume if volume is controlled by effect
@ -5096,6 +5110,7 @@ void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTr
}
if (lastTrack) {
track->setFinalVolume((left + right) / 2.f);
if (left != mLeftVolFloat || right != mRightVolFloat) {
mLeftVolFloat = left;
mRightVolFloat = right;
@ -6153,14 +6168,12 @@ bool AudioFlinger::DuplicatingThread::outputsReady(
return true;
}
void AudioFlinger::DuplicatingThread::updateMetadata_l()
void AudioFlinger::DuplicatingThread::sendMetadataToBackend_l(
const StreamOutHalInterface::SourceMetadata& metadata)
{
// TODO: The duplicated track metadata needs to be pushed to downstream
// but this information can be read at any time by the downstream threads.
// Taking the lock of any downstream threads is no possible due to cross deadlock risks
// (eg: during effect move).
// A lock-free structure needs to be used to shared the metadata, probably an atomic
// pointer to a metadata vector in each output tracks.
for (auto& outputTrack : outputTracks) { // not mOutputTracks
outputTrack->setMetadatas(metadata.tracks);
}
}
uint32_t AudioFlinger::DuplicatingThread::activeSleepTimeUs() const

@ -566,8 +566,8 @@ protected:
// periodically called in the threadLoop() to update power state uids.
void updatePowerState(sp<ThreadBase> thread, bool force = false);
/** @return true if the active tracks have changed since the last time
* this function was called or the vector was created. */
/** @return true if one or move active tracks was added or removed since the
* last time this function was called or the vector was created. */
bool readAndClearHasChanged();
private:
@ -588,7 +588,7 @@ protected:
int mLastActiveTracksGeneration;
wp<T> mLatestActiveTrack; // latest track added to ActiveTracks
SimpleLog * const mLocalLog;
// If the active tracks have changed since last call to readAndClearHasChanged
// If the vector has changed since last call to readAndClearHasChanged
bool mHasChanged = false;
};
@ -927,7 +927,8 @@ private:
void removeTrack_l(const sp<Track>& track);
void readOutputParameters_l();
void updateMetadata_l() override;
void updateMetadata_l() final;
virtual void sendMetadataToBackend_l(const StreamOutHalInterface::SourceMetadata& metadata);
virtual void dumpInternals(int fd, const Vector<String16>& args);
void dumpTracks(int fd, const Vector<String16>& args);
@ -1287,7 +1288,8 @@ public:
void removeOutputTrack(MixerThread* thread);
uint32_t waitTimeMs() const { return mWaitTimeMs; }
void updateMetadata_l() override;
void sendMetadataToBackend_l(
const StreamOutHalInterface::SourceMetadata& metadata) override;
protected:
virtual uint32_t activeSleepTimeUs() const;

@ -407,6 +407,9 @@ AudioFlinger::PlaybackThread::Track::Track(
// mSinkTimestamp
mFastIndex(-1),
mCachedVolume(1.0),
/* The track might not play immediately after being active, similarly as if its volume was 0.
* When the track starts playing, its volume will be computed. */
mFinalVolume(0.f),
mResumeToStopping(false),
mFlushHwPending(false),
mFlags(flags)
@ -997,6 +1000,23 @@ sp<VolumeShaper::State> AudioFlinger::PlaybackThread::Track::getVolumeShaperStat
return mVolumeHandler->getVolumeShaperState(id);
}
void AudioFlinger::PlaybackThread::Track::setFinalVolume(float volume)
{
if (mFinalVolume != volume) { // Compare to an epsilon if too many meaningless updates
mFinalVolume = volume;
setMetadataHasChanged();
}
}
void AudioFlinger::PlaybackThread::Track::copyMetadataTo(MetadataInserter& backInserter) const
{
*backInserter++ = {
.usage = mAttr.usage,
.content_type = mAttr.content_type,
.gain = mFinalVolume,
};
}
status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& timestamp)
{
if (!isOffloaded() && !isDirect()) {
@ -1427,6 +1447,21 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frame
return outputBufferFull;
}
void AudioFlinger::PlaybackThread::OutputTrack::copyMetadataTo(MetadataInserter& backInserter) const
{
std::lock_guard<std::mutex> lock(mTrackMetadatasMutex);
backInserter = std::copy(mTrackMetadatas.begin(), mTrackMetadatas.end(), backInserter);
}
void AudioFlinger::PlaybackThread::OutputTrack::setMetadatas(const SourceMetadatas& metadatas) {
{
std::lock_guard<std::mutex> lock(mTrackMetadatasMutex);
mTrackMetadatas = metadatas;
}
// No need to adjust metadata track volumes as OutputTrack volumes are always 0dBFS.
setMetadataHasChanged();
}
status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer(
AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs)
{

Loading…
Cancel
Save