summaryrefslogtreecommitdiffstats
path: root/services/audioflinger/AudioFlinger.cpp
diff options
context:
space:
mode:
authorGlenn Kasten <gkasten@google.com>2012-11-01 11:57:08 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2012-11-01 11:57:08 -0700
commit5fe6138bd839297a1eed16885102b3bdfc98c040 (patch)
treefc174c6734216926b8443f07dfaa3e7641de3441 /services/audioflinger/AudioFlinger.cpp
parent3208d28bb3b77970ce4a172d741014291d36dd2f (diff)
parentd06785bebf7e43d4a011b62a252771373ada910c (diff)
downloadframeworks_av-5fe6138bd839297a1eed16885102b3bdfc98c040.zip
frameworks_av-5fe6138bd839297a1eed16885102b3bdfc98c040.tar.gz
frameworks_av-5fe6138bd839297a1eed16885102b3bdfc98c040.tar.bz2
Merge "Save copy of mic input, disabled by default"
Diffstat (limited to 'services/audioflinger/AudioFlinger.cpp')
-rw-r--r--services/audioflinger/AudioFlinger.cpp133
1 files changed, 101 insertions, 32 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 096a0f0..9bdab2f 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -417,6 +417,12 @@ status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
audio_hw_device_t *dev = mAudioHwDevs.valueAt(i)->hwDevice();
dev->dump(dev, fd);
}
+
+ // dump the serially shared record tee sink
+ if (mRecordTeeSource != 0) {
+ dumpTee(fd, mRecordTeeSource);
+ }
+
if (locked) mLock.unlock();
}
return NO_ERROR;
@@ -3580,39 +3586,18 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
return reconfig;
}
-void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id)
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- PlaybackThread::dumpInternals(fd, args);
-
- snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
- result.append(buffer);
- write(fd, result.string(), result.size());
-
- // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
- FastMixerDumpState copy = mFastMixerDumpState;
- copy.dump(fd);
-
-#ifdef STATE_QUEUE_DUMP
- // Similar for state queue
- StateQueueObserverDump observerCopy = mStateQueueObserverDump;
- observerCopy.dump(fd);
- StateQueueMutatorDump mutatorCopy = mStateQueueMutatorDump;
- mutatorCopy.dump(fd);
-#endif
-
- // Write the tee output to a .wav file
- NBAIO_Source *teeSource = mTeeSource.get();
+ NBAIO_Source *teeSource = source.get();
if (teeSource != NULL) {
- char teePath[64];
+ char teeTime[16];
struct timeval tv;
gettimeofday(&tv, NULL);
struct tm tm;
localtime_r(&tv.tv_sec, &tm);
- strftime(teePath, sizeof(teePath), "/data/misc/media/%T.wav", &tm);
+ strftime(teeTime, sizeof(teeTime), "%T", &tm);
+ char teePath[64];
+ sprintf(teePath, "/data/misc/media/%s_%d.wav", teeTime, id);
int teeFd = open(teePath, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
if (teeFd >= 0) {
char wavHeader[44];
@@ -3660,6 +3645,34 @@ void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& ar
fdprintf(fd, "FastMixer unable to create tee %s: \n", strerror(errno));
}
}
+}
+
+void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>& args)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ PlaybackThread::dumpInternals(fd, args);
+
+ snprintf(buffer, SIZE, "AudioMixer tracks: %08x\n", mAudioMixer->trackNames());
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+
+ // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
+ FastMixerDumpState copy = mFastMixerDumpState;
+ copy.dump(fd);
+
+#ifdef STATE_QUEUE_DUMP
+ // Similar for state queue
+ StateQueueObserverDump observerCopy = mStateQueueObserverDump;
+ observerCopy.dump(fd);
+ StateQueueMutatorDump mutatorCopy = mStateQueueMutatorDump;
+ mutatorCopy.dump(fd);
+#endif
+
+ // Write the tee output to a .wav file
+ dumpTee(fd, mTeeSource, mId);
#ifdef AUDIO_WATCHDOG
if (mAudioWatchdog != 0) {
@@ -5988,18 +6001,21 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
uint32_t sampleRate,
audio_channel_mask_t channelMask,
audio_io_handle_t id,
- audio_devices_t device) :
+ audio_devices_t device,
+ const sp<NBAIO_Sink>& teeSink) :
ThreadBase(audioFlinger, id, AUDIO_DEVICE_NONE, device, RECORD),
mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
// mRsmpInIndex and mInputBytes set by readInputParameters()
mReqChannelCount(popcount(channelMask)),
- mReqSampleRate(sampleRate)
+ mReqSampleRate(sampleRate),
// mBytesRead is only meaningful while active, and so is cleared in start()
// (but might be better to also clear here for dump?)
+ mTeeSink(teeSink)
{
snprintf(mName, kNameLength, "AudioIn_%X", id);
readInputParameters();
+
}
@@ -6125,14 +6141,16 @@ bool AudioFlinger::RecordThread::threadLoop()
}
}
if (framesOut && mFrameCount == mRsmpInIndex) {
+ void *readInto;
if (framesOut == mFrameCount &&
((int)mChannelCount == mReqChannelCount || mFormat != AUDIO_FORMAT_PCM_16_BIT)) {
- mBytesRead = mInput->stream->read(mInput->stream, buffer.raw, mInputBytes);
+ readInto = buffer.raw;
framesOut = 0;
} else {
- mBytesRead = mInput->stream->read(mInput->stream, mRsmpInBuffer, mInputBytes);
+ readInto = mRsmpInBuffer;
mRsmpInIndex = 0;
}
+ mBytesRead = mInput->stream->read(mInput->stream, readInto, mInputBytes);
if (mBytesRead <= 0) {
if ((mBytesRead < 0) && (mActiveTrack->mState == TrackBase::ACTIVE))
{
@@ -6145,6 +6163,9 @@ bool AudioFlinger::RecordThread::threadLoop()
mRsmpInIndex = mFrameCount;
framesOut = 0;
buffer.frameCount = 0;
+ } else if (mTeeSink != 0) {
+ (void) mTeeSink->write(readInto,
+ mBytesRead >> Format_frameBitShift(mTeeSink->format()));
}
}
}
@@ -7184,18 +7205,66 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module,
}
if (status == NO_ERROR && inStream != NULL) {
+
+ // Try to re-use most recently used Pipe to archive a copy of input for dumpsys,
+ // or (re-)create if current Pipe is idle and does not match the new format
+ sp<NBAIO_Sink> teeSink;
+#ifdef TEE_SINK_INPUT_FRAMES
+ enum {
+ TEE_SINK_NO, // don't copy input
+ TEE_SINK_NEW, // copy input using a new pipe
+ TEE_SINK_OLD, // copy input using an existing pipe
+ } kind;
+ NBAIO_Format format = Format_from_SR_C(inStream->common.get_sample_rate(&inStream->common),
+ popcount(inStream->common.get_channels(&inStream->common)));
+ if (format == Format_Invalid) {
+ kind = TEE_SINK_NO;
+ } else if (mRecordTeeSink == 0) {
+ kind = TEE_SINK_NEW;
+ } else if (mRecordTeeSink->getStrongCount() != 1) {
+ kind = TEE_SINK_NO;
+ } else if (format == mRecordTeeSink->format()) {
+ kind = TEE_SINK_OLD;
+ } else {
+ kind = TEE_SINK_NEW;
+ }
+ switch (kind) {
+ case TEE_SINK_NEW: {
+ Pipe *pipe = new Pipe(TEE_SINK_INPUT_FRAMES, format);
+ size_t numCounterOffers = 0;
+ const NBAIO_Format offers[1] = {format};
+ ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
+ ALOG_ASSERT(index == 0);
+ PipeReader *pipeReader = new PipeReader(*pipe);
+ numCounterOffers = 0;
+ index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
+ ALOG_ASSERT(index == 0);
+ mRecordTeeSink = pipe;
+ mRecordTeeSource = pipeReader;
+ teeSink = pipe;
+ }
+ break;
+ case TEE_SINK_OLD:
+ teeSink = mRecordTeeSink;
+ break;
+ case TEE_SINK_NO:
+ default:
+ break;
+ }
+#endif
AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream);
// Start record thread
// RecorThread require both input and output device indication to forward to audio
// pre processing modules
audio_devices_t device = (*pDevices) | primaryOutputDevice_l();
+
thread = new RecordThread(this,
input,
reqSamplingRate,
reqChannels,
id,
- device);
+ device, teeSink);
mRecordThreads.add(id, thread);
ALOGV("openInput() created record thread: ID %d thread %p", id, thread);
if (pSamplingRate != NULL) *pSamplingRate = reqSamplingRate;