|
|
|
@ -57,6 +57,7 @@
|
|
|
|
|
#include <powermanager/PowerManager.h>
|
|
|
|
|
|
|
|
|
|
#include <media/audiohal/EffectsFactoryHalInterface.h>
|
|
|
|
|
#include <media/audiohal/StreamHalInterface.h>
|
|
|
|
|
|
|
|
|
|
#include "AudioFlinger.h"
|
|
|
|
|
#include "FastMixer.h"
|
|
|
|
@ -1554,6 +1555,7 @@ ssize_t AudioFlinger::ThreadBase::ActiveTracks<T>::add(const sp<T> &track) {
|
|
|
|
|
mActiveTracksGeneration++;
|
|
|
|
|
mLatestActiveTrack = track;
|
|
|
|
|
++mBatteryCounter[track->uid()].second;
|
|
|
|
|
mHasChanged = true;
|
|
|
|
|
return mActiveTracks.add(track);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1568,6 +1570,7 @@ ssize_t AudioFlinger::ThreadBase::ActiveTracks<T>::remove(const sp<T> &track) {
|
|
|
|
|
mActiveTracksGeneration++;
|
|
|
|
|
--mBatteryCounter[track->uid()].second;
|
|
|
|
|
// mLatestActiveTrack is not cleared even if is the same as track.
|
|
|
|
|
mHasChanged = true;
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1578,6 +1581,7 @@ void AudioFlinger::ThreadBase::ActiveTracks<T>::clear() {
|
|
|
|
|
logTrack("clear", track);
|
|
|
|
|
}
|
|
|
|
|
mLastActiveTracksGeneration = mActiveTracksGeneration;
|
|
|
|
|
if (!mActiveTracks.empty()) { mHasChanged = true; }
|
|
|
|
|
mActiveTracks.clear();
|
|
|
|
|
mLatestActiveTrack.clear();
|
|
|
|
|
mBatteryCounter.clear();
|
|
|
|
@ -1614,6 +1618,13 @@ void AudioFlinger::ThreadBase::ActiveTracks<T>::updatePowerState(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
bool AudioFlinger::ThreadBase::ActiveTracks<T>::readAndClearHasChanged() {
|
|
|
|
|
const bool hasChanged = mHasChanged;
|
|
|
|
|
mHasChanged = false;
|
|
|
|
|
return hasChanged;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
void AudioFlinger::ThreadBase::ActiveTracks<T>::logTrack(
|
|
|
|
|
const char *funcName, const sp<T> &track) const {
|
|
|
|
@ -1847,6 +1858,7 @@ void AudioFlinger::PlaybackThread::preExit()
|
|
|
|
|
sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrack_l(
|
|
|
|
|
const sp<AudioFlinger::Client>& client,
|
|
|
|
|
audio_stream_type_t streamType,
|
|
|
|
|
const audio_attributes_t& attr,
|
|
|
|
|
uint32_t *pSampleRate,
|
|
|
|
|
audio_format_t format,
|
|
|
|
|
audio_channel_mask_t channelMask,
|
|
|
|
@ -2125,7 +2137,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
track = new Track(this, client, streamType, sampleRate, format,
|
|
|
|
|
track = new Track(this, client, streamType, attr, sampleRate, format,
|
|
|
|
|
channelMask, frameCount,
|
|
|
|
|
nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
|
|
|
|
|
sessionId, uid, *flags, TrackBase::TYPE_DEFAULT, portId);
|
|
|
|
@ -2609,6 +2621,24 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AudioFlinger::PlaybackThread::updateMetadata_l()
|
|
|
|
|
{
|
|
|
|
|
// TODO: add volume support
|
|
|
|
|
if (mOutput == nullptr || mOutput->stream == nullptr ||
|
|
|
|
|
!mActiveTracks.readAndClearHasChanged()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
StreamOutHalInterface::SourceMetadata metadata;
|
|
|
|
|
for (const sp<Track> &track : mActiveTracks) {
|
|
|
|
|
// No track is invalid as this is called after prepareTrack_l in the same critical section
|
|
|
|
|
metadata.tracks.push_back({
|
|
|
|
|
.usage = track->attributes().usage,
|
|
|
|
|
.content_type = track->attributes().content_type,
|
|
|
|
|
.gain = 1,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
mOutput->stream->updateSourceMetadata(metadata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames)
|
|
|
|
|
{
|
|
|
|
@ -3306,6 +3336,8 @@ bool AudioFlinger::PlaybackThread::threadLoop()
|
|
|
|
|
|
|
|
|
|
mActiveTracks.updatePowerState(this);
|
|
|
|
|
|
|
|
|
|
updateMetadata_l();
|
|
|
|
|
|
|
|
|
|
// prevent any changes in effect chain list and in each effect chain
|
|
|
|
|
// during mixing and effect process as the audio buffers could be deleted
|
|
|
|
|
// or modified if an effect is created or deleted
|
|
|
|
@ -6117,6 +6149,17 @@ bool AudioFlinger::DuplicatingThread::outputsReady(
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AudioFlinger::DuplicatingThread::updateMetadata_l()
|
|
|
|
|
{
|
|
|
|
|
// TODO: The duplicated track metadata are stored in other threads
|
|
|
|
|
// (accessible through mActiveTracks::OutputTrack::thread()::mActiveTracks::Track::attributes())
|
|
|
|
|
// but this information can be mutated at any time by the owning threads.
|
|
|
|
|
// Taking the lock of any other owning threads is no possible due to timing constrains.
|
|
|
|
|
// Similarly, the other threads can not push the metadatas in this thread as cross deadlock
|
|
|
|
|
// would be possible.
|
|
|
|
|
// A lock-free structure needs to be used to shared the metadata (maybe an atomic shared_ptr ?).
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t AudioFlinger::DuplicatingThread::activeSleepTimeUs() const
|
|
|
|
|
{
|
|
|
|
|
return (mWaitTimeMs * 1000) / 2;
|
|
|
|
@ -6444,6 +6487,8 @@ reacquire_wakelock:
|
|
|
|
|
|
|
|
|
|
mActiveTracks.updatePowerState(this);
|
|
|
|
|
|
|
|
|
|
updateMetadata_l();
|
|
|
|
|
|
|
|
|
|
if (allStopped) {
|
|
|
|
|
standbyIfNotAlreadyInStandby();
|
|
|
|
|
}
|
|
|
|
@ -6808,6 +6853,7 @@ void AudioFlinger::RecordThread::inputStandBy()
|
|
|
|
|
// RecordThread::createRecordTrack_l() must be called with AudioFlinger::mLock held
|
|
|
|
|
sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
|
|
|
|
|
const sp<AudioFlinger::Client>& client,
|
|
|
|
|
const audio_attributes_t& attr,
|
|
|
|
|
uint32_t *pSampleRate,
|
|
|
|
|
audio_format_t format,
|
|
|
|
|
audio_channel_mask_t channelMask,
|
|
|
|
@ -6941,7 +6987,7 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRe
|
|
|
|
|
{ // scope for mLock
|
|
|
|
|
Mutex::Autolock _l(mLock);
|
|
|
|
|
|
|
|
|
|
track = new RecordTrack(this, client, sampleRate,
|
|
|
|
|
track = new RecordTrack(this, client, attr, sampleRate,
|
|
|
|
|
format, channelMask, frameCount,
|
|
|
|
|
nullptr /* buffer */, (size_t)0 /* bufferSize */, sessionId, uid,
|
|
|
|
|
*flags, TrackBase::TYPE_DEFAULT, portId);
|
|
|
|
@ -7133,6 +7179,23 @@ status_t AudioFlinger::RecordThread::getActiveMicrophones(
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AudioFlinger::RecordThread::updateMetadata_l()
|
|
|
|
|
{
|
|
|
|
|
if (mInput == nullptr || mInput->stream == nullptr ||
|
|
|
|
|
!mActiveTracks.readAndClearHasChanged()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
StreamInHalInterface::SinkMetadata metadata;
|
|
|
|
|
for (const sp<RecordTrack> &track : mActiveTracks) {
|
|
|
|
|
// No track is invalid as this is called after prepareTrack_l in the same critical section
|
|
|
|
|
metadata.tracks.push_back({
|
|
|
|
|
.source = track->attributes().source,
|
|
|
|
|
.gain = 1, // capture tracks do not have volumes
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
mInput->stream->updateSinkMetadata(metadata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// destroyTrack_l() must be called with ThreadBase::mLock held
|
|
|
|
|
void AudioFlinger::RecordThread::destroyTrack_l(const sp<RecordTrack>& track)
|
|
|
|
|
{
|
|
|
|
@ -7960,7 +8023,8 @@ status_t AudioFlinger::MmapThread::start(const AudioClient& client,
|
|
|
|
|
return PERMISSION_DENIED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sp<MmapTrack> track = new MmapTrack(this, mSampleRate, mFormat, mChannelMask, mSessionId,
|
|
|
|
|
// Given that MmapThread::mAttr is mutable, should a MmapTrack have attributes ?
|
|
|
|
|
sp<MmapTrack> track = new MmapTrack(this, mAttr, mSampleRate, mFormat, mChannelMask, mSessionId,
|
|
|
|
|
client.clientUid, client.clientPid, portId);
|
|
|
|
|
|
|
|
|
|
mActiveTracks.add(track);
|
|
|
|
@ -8096,6 +8160,8 @@ bool AudioFlinger::MmapThread::threadLoop()
|
|
|
|
|
|
|
|
|
|
mActiveTracks.updatePowerState(this);
|
|
|
|
|
|
|
|
|
|
updateMetadata_l();
|
|
|
|
|
|
|
|
|
|
lockEffectChains_l(effectChains);
|
|
|
|
|
for (size_t i = 0; i < effectChains.size(); i ++) {
|
|
|
|
|
effectChains[i]->process_l();
|
|
|
|
@ -8643,6 +8709,24 @@ void AudioFlinger::MmapPlaybackThread::processVolume_l()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AudioFlinger::MmapPlaybackThread::updateMetadata_l()
|
|
|
|
|
{
|
|
|
|
|
if (mOutput == nullptr || mOutput->stream == nullptr ||
|
|
|
|
|
!mActiveTracks.readAndClearHasChanged()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
StreamOutHalInterface::SourceMetadata metadata;
|
|
|
|
|
for (const sp<MmapTrack> &track : mActiveTracks) {
|
|
|
|
|
// No track is invalid as this is called after prepareTrack_l in the same critical section
|
|
|
|
|
metadata.tracks.push_back({
|
|
|
|
|
.usage = track->attributes().usage,
|
|
|
|
|
.content_type = track->attributes().content_type,
|
|
|
|
|
.gain = mHalVolFloat, // TODO: propagate from aaudio pre-mix volume
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
mOutput->stream->updateSourceMetadata(metadata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AudioFlinger::MmapPlaybackThread::checkSilentMode_l()
|
|
|
|
|
{
|
|
|
|
|
if (!mMasterMute) {
|
|
|
|
@ -8687,4 +8771,22 @@ AudioFlinger::AudioStreamIn* AudioFlinger::MmapCaptureThread::clearInput()
|
|
|
|
|
mInput = NULL;
|
|
|
|
|
return input;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AudioFlinger::MmapCaptureThread::updateMetadata_l()
|
|
|
|
|
{
|
|
|
|
|
if (mInput == nullptr || mInput->stream == nullptr ||
|
|
|
|
|
!mActiveTracks.readAndClearHasChanged()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
StreamInHalInterface::SinkMetadata metadata;
|
|
|
|
|
for (const sp<MmapTrack> &track : mActiveTracks) {
|
|
|
|
|
// No track is invalid as this is called after prepareTrack_l in the same critical section
|
|
|
|
|
metadata.tracks.push_back({
|
|
|
|
|
.source = track->attributes().source,
|
|
|
|
|
.gain = 1, // capture tracks do not have volumes
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
mInput->stream->updateSinkMetadata(metadata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace android
|
|
|
|
|