Loading services/audioflinger/Android.mk +0 −8 Original line number Original line Diff line number Diff line Loading @@ -66,14 +66,6 @@ LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"' LOCAL_CFLAGS += -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE LOCAL_CFLAGS += -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE # uncomment for dumpsys to write most recent audio output to .wav file # 47.5 seconds at 44.1 kHz, 8 megabytes # LOCAL_CFLAGS += -DTEE_SINK_FRAMES=0x200000 # uncomment for dumpsys to write most recent audio input to .wav file # 47.5 seconds at 44.1 kHz, 8 megabytes # LOCAL_CFLAGS += -DTEE_SINK_INPUT_FRAMES=0x200000 # uncomment to enable the audio watchdog # uncomment to enable the audio watchdog # LOCAL_SRC_FILES += AudioWatchdog.cpp # LOCAL_SRC_FILES += AudioWatchdog.cpp # LOCAL_CFLAGS += -DAUDIO_WATCHDOG # LOCAL_CFLAGS += -DAUDIO_WATCHDOG Loading services/audioflinger/AudioFlinger.cpp +101 −10 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #define LOG_TAG "AudioFlinger" #define LOG_TAG "AudioFlinger" //#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0 #include <dirent.h> #include <math.h> #include <math.h> #include <signal.h> #include <signal.h> #include <sys/time.h> #include <sys/time.h> Loading Loading @@ -61,6 +62,9 @@ #include <media/IMediaLogService.h> #include <media/IMediaLogService.h> #include <media/nbaio/Pipe.h> #include <media/nbaio/PipeReader.h> // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Note: the following macro is used for extremely verbose logging message. In // Note: the following macro is used for extremely verbose logging message. In Loading @@ -86,6 +90,14 @@ nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs; uint32_t AudioFlinger::mScreenState; uint32_t AudioFlinger::mScreenState; bool AudioFlinger::mTeeSinkInputEnabled = false; bool AudioFlinger::mTeeSinkOutputEnabled = false; bool AudioFlinger::mTeeSinkTrackEnabled = false; size_t AudioFlinger::mTeeSinkInputFrames = kTeeSinkInputFramesDefault; size_t AudioFlinger::mTeeSinkOutputFrames = kTeeSinkOutputFramesDefault; size_t AudioFlinger::mTeeSinkTrackFrames = kTeeSinkTrackFramesDefault; // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- static int load_audio_interface(const char *if_name, audio_hw_device_t **dev) static int load_audio_interface(const char *if_name, audio_hw_device_t **dev) Loading Loading @@ -134,6 +146,19 @@ AudioFlinger::AudioFlinger() if (doLog) { if (doLog) { mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters"); mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters"); } } (void) property_get("ro.debuggable", value, "0"); int debuggable = atoi(value); int teeEnabled = 0; if (debuggable) { (void) property_get("af.tee", value, "0"); teeEnabled = atoi(value); } if (teeEnabled & 1) mTeeSinkInputEnabled = true; if (teeEnabled & 2) mTeeSinkOutputEnabled = true; if (teeEnabled & 4) mTeeSinkTrackEnabled = true; } } void AudioFlinger::onFirstRef() void AudioFlinger::onFirstRef() Loading Loading @@ -1602,7 +1627,6 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, // Try to re-use most recently used Pipe to archive a copy of input for dumpsys, // 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 // or (re-)create if current Pipe is idle and does not match the new format sp<NBAIO_Sink> teeSink; sp<NBAIO_Sink> teeSink; #ifdef TEE_SINK_INPUT_FRAMES enum { enum { TEE_SINK_NO, // don't copy input TEE_SINK_NO, // don't copy input TEE_SINK_NEW, // copy input using a new pipe TEE_SINK_NEW, // copy input using a new pipe Loading @@ -1610,7 +1634,9 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, } kind; } kind; NBAIO_Format format = Format_from_SR_C(inStream->common.get_sample_rate(&inStream->common), NBAIO_Format format = Format_from_SR_C(inStream->common.get_sample_rate(&inStream->common), popcount(inStream->common.get_channels(&inStream->common))); popcount(inStream->common.get_channels(&inStream->common))); if (format == Format_Invalid) { if (!mTeeSinkInputEnabled) { kind = TEE_SINK_NO; } else if (format == Format_Invalid) { kind = TEE_SINK_NO; kind = TEE_SINK_NO; } else if (mRecordTeeSink == 0) { } else if (mRecordTeeSink == 0) { kind = TEE_SINK_NEW; kind = TEE_SINK_NEW; Loading @@ -1623,7 +1649,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, } } switch (kind) { switch (kind) { case TEE_SINK_NEW: { case TEE_SINK_NEW: { Pipe *pipe = new Pipe(TEE_SINK_INPUT_FRAMES, format); Pipe *pipe = new Pipe(mTeeSinkInputFrames, format); size_t numCounterOffers = 0; size_t numCounterOffers = 0; const NBAIO_Format offers[1] = {format}; const NBAIO_Format offers[1] = {format}; ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers); ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers); Loading @@ -1644,7 +1670,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, default: default: break; break; } } #endif AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream); AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream); // Start record thread // Start record thread Loading Loading @@ -2199,19 +2225,80 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId, return NO_ERROR; return NO_ERROR; } } struct Entry { #define MAX_NAME 32 // %Y%m%d%H%M%S_%d.wav char mName[MAX_NAME]; }; int comparEntry(const void *p1, const void *p2) { return strcmp(((const Entry *) p1)->mName, ((const Entry *) p2)->mName); } void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id) void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id) { { NBAIO_Source *teeSource = source.get(); NBAIO_Source *teeSource = source.get(); if (teeSource != NULL) { if (teeSource != NULL) { // .wav rotation // There is a benign race condition if 2 threads call this simultaneously. // They would both traverse the directory, but the result would simply be // failures at unlink() which are ignored. It's also unlikely since // normally dumpsys is only done by bugreport or from the command line. char teePath[32+256]; strcpy(teePath, "/data/misc/media"); size_t teePathLen = strlen(teePath); DIR *dir = opendir(teePath); teePath[teePathLen++] = '/'; if (dir != NULL) { #define MAX_SORT 20 // number of entries to sort #define MAX_KEEP 10 // number of entries to keep struct Entry entries[MAX_SORT]; size_t entryCount = 0; while (entryCount < MAX_SORT) { struct dirent de; struct dirent *result = NULL; int rc = readdir_r(dir, &de, &result); if (rc != 0) { ALOGW("readdir_r failed %d", rc); break; } if (result == NULL) { break; } if (result != &de) { ALOGW("readdir_r returned unexpected result %p != %p", result, &de); break; } // ignore non .wav file entries size_t nameLen = strlen(de.d_name); if (nameLen <= 4 || nameLen >= MAX_NAME || strcmp(&de.d_name[nameLen - 4], ".wav")) { continue; } strcpy(entries[entryCount++].mName, de.d_name); } (void) closedir(dir); if (entryCount > MAX_KEEP) { qsort(entries, entryCount, sizeof(Entry), comparEntry); for (size_t i = 0; i < entryCount - MAX_KEEP; ++i) { strcpy(&teePath[teePathLen], entries[i].mName); (void) unlink(teePath); } } } else { if (fd >= 0) { fdprintf(fd, "unable to rotate tees in %s: %s\n", teePath, strerror(errno)); } } char teeTime[16]; char teeTime[16]; struct timeval tv; struct timeval tv; gettimeofday(&tv, NULL); gettimeofday(&tv, NULL); struct tm tm; struct tm tm; localtime_r(&tv.tv_sec, &tm); localtime_r(&tv.tv_sec, &tm); strftime(teeTime, sizeof(teeTime), "%T", &tm); strftime(teeTime, sizeof(teeTime), "%Y%m%d%H%M%S", &tm); char teePath[64]; snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d.wav", teeTime, id); sprintf(teePath, "/data/misc/media/%s_%d.wav", teeTime, id); // if 2 dumpsys are done within 1 second, and rotation didn't work, then discard 2nd int teeFd = open(teePath, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); int teeFd = open(teePath, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR); if (teeFd >= 0) { if (teeFd >= 0) { char wavHeader[44]; char wavHeader[44]; memcpy(wavHeader, memcpy(wavHeader, Loading Loading @@ -2253,9 +2340,13 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand temp = total * channelCount * sizeof(short); temp = total * channelCount * sizeof(short); write(teeFd, &temp, sizeof(temp)); write(teeFd, &temp, sizeof(temp)); close(teeFd); close(teeFd); fdprintf(fd, "FastMixer tee copied to %s\n", teePath); if (fd >= 0) { fdprintf(fd, "tee copied to %s\n", teePath); } } else { } else { fdprintf(fd, "FastMixer unable to create tee %s: \n", strerror(errno)); if (fd >= 0) { fdprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno)); } } } } } } } Loading services/audioflinger/AudioFlinger.h +17 −0 Original line number Original line Diff line number Diff line Loading @@ -593,7 +593,24 @@ private: sp<NBAIO_Source> mRecordTeeSource; sp<NBAIO_Source> mRecordTeeSource; public: public: // tee sink, if enabled by property, allows dumpsys to write most recent audio to .wav file static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id = 0); static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id = 0); // whether tee sink is enabled by property static bool mTeeSinkInputEnabled; static bool mTeeSinkOutputEnabled; static bool mTeeSinkTrackEnabled; // runtime configured size of each tee sink pipe, in frames static size_t mTeeSinkInputFrames; static size_t mTeeSinkOutputFrames; static size_t mTeeSinkTrackFrames; // compile-time default size of tee sink pipes, in frames // 0x200000 stereo 16-bit PCM frames = 47.5 seconds at 44.1 kHz, 8 megabytes static const size_t kTeeSinkInputFramesDefault = 0x200000; static const size_t kTeeSinkOutputFramesDefault = 0x200000; static const size_t kTeeSinkTrackFramesDefault = 0x1000; }; }; #undef INCLUDING_FROM_AUDIOFLINGER_H #undef INCLUDING_FROM_AUDIOFLINGER_H Loading services/audioflinger/Threads.cpp +13 −13 Original line number Original line Diff line number Diff line Loading @@ -2124,9 +2124,9 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud (monoPipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2); (monoPipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2); mPipeSink = monoPipe; mPipeSink = monoPipe; #ifdef TEE_SINK_FRAMES if (mTeeSinkOutputEnabled) { // create a Pipe to archive a copy of FastMixer's output for dumpsys // create a Pipe to archive a copy of FastMixer's output for dumpsys Pipe *teeSink = new Pipe(TEE_SINK_FRAMES, format); Pipe *teeSink = new Pipe(mTeeSinkOutputFrames, format); numCounterOffers = 0; numCounterOffers = 0; index = teeSink->negotiate(offers, 1, NULL, numCounterOffers); index = teeSink->negotiate(offers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); ALOG_ASSERT(index == 0); Loading @@ -2136,7 +2136,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud index = teeSource->negotiate(offers, 1, NULL, numCounterOffers); index = teeSource->negotiate(offers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); ALOG_ASSERT(index == 0); mTeeSource = teeSource; mTeeSource = teeSource; #endif } // create fast mixer and configure it initially with just one fast track for our submix // create fast mixer and configure it initially with just one fast track for our submix mFastMixer = new FastMixer(); mFastMixer = new FastMixer(); Loading services/audioflinger/TrackBase.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -141,4 +141,7 @@ protected: Vector < sp<SyncEvent> >mSyncEvents; Vector < sp<SyncEvent> >mSyncEvents; const bool mIsOut; const bool mIsOut; ServerProxy* mServerProxy; ServerProxy* mServerProxy; const int mId; sp<NBAIO_Sink> mTeeSink; sp<NBAIO_Source> mTeeSource; }; }; Loading
services/audioflinger/Android.mk +0 −8 Original line number Original line Diff line number Diff line Loading @@ -66,14 +66,6 @@ LOCAL_CFLAGS += -DSTATE_QUEUE_INSTANTIATIONS='"StateQueueInstantiations.cpp"' LOCAL_CFLAGS += -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE LOCAL_CFLAGS += -UFAST_TRACKS_AT_NON_NATIVE_SAMPLE_RATE # uncomment for dumpsys to write most recent audio output to .wav file # 47.5 seconds at 44.1 kHz, 8 megabytes # LOCAL_CFLAGS += -DTEE_SINK_FRAMES=0x200000 # uncomment for dumpsys to write most recent audio input to .wav file # 47.5 seconds at 44.1 kHz, 8 megabytes # LOCAL_CFLAGS += -DTEE_SINK_INPUT_FRAMES=0x200000 # uncomment to enable the audio watchdog # uncomment to enable the audio watchdog # LOCAL_SRC_FILES += AudioWatchdog.cpp # LOCAL_SRC_FILES += AudioWatchdog.cpp # LOCAL_CFLAGS += -DAUDIO_WATCHDOG # LOCAL_CFLAGS += -DAUDIO_WATCHDOG Loading
services/audioflinger/AudioFlinger.cpp +101 −10 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ #define LOG_TAG "AudioFlinger" #define LOG_TAG "AudioFlinger" //#define LOG_NDEBUG 0 //#define LOG_NDEBUG 0 #include <dirent.h> #include <math.h> #include <math.h> #include <signal.h> #include <signal.h> #include <sys/time.h> #include <sys/time.h> Loading Loading @@ -61,6 +62,9 @@ #include <media/IMediaLogService.h> #include <media/IMediaLogService.h> #include <media/nbaio/Pipe.h> #include <media/nbaio/PipeReader.h> // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- // Note: the following macro is used for extremely verbose logging message. In // Note: the following macro is used for extremely verbose logging message. In Loading @@ -86,6 +90,14 @@ nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs; uint32_t AudioFlinger::mScreenState; uint32_t AudioFlinger::mScreenState; bool AudioFlinger::mTeeSinkInputEnabled = false; bool AudioFlinger::mTeeSinkOutputEnabled = false; bool AudioFlinger::mTeeSinkTrackEnabled = false; size_t AudioFlinger::mTeeSinkInputFrames = kTeeSinkInputFramesDefault; size_t AudioFlinger::mTeeSinkOutputFrames = kTeeSinkOutputFramesDefault; size_t AudioFlinger::mTeeSinkTrackFrames = kTeeSinkTrackFramesDefault; // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- static int load_audio_interface(const char *if_name, audio_hw_device_t **dev) static int load_audio_interface(const char *if_name, audio_hw_device_t **dev) Loading Loading @@ -134,6 +146,19 @@ AudioFlinger::AudioFlinger() if (doLog) { if (doLog) { mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters"); mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters"); } } (void) property_get("ro.debuggable", value, "0"); int debuggable = atoi(value); int teeEnabled = 0; if (debuggable) { (void) property_get("af.tee", value, "0"); teeEnabled = atoi(value); } if (teeEnabled & 1) mTeeSinkInputEnabled = true; if (teeEnabled & 2) mTeeSinkOutputEnabled = true; if (teeEnabled & 4) mTeeSinkTrackEnabled = true; } } void AudioFlinger::onFirstRef() void AudioFlinger::onFirstRef() Loading Loading @@ -1602,7 +1627,6 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, // Try to re-use most recently used Pipe to archive a copy of input for dumpsys, // 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 // or (re-)create if current Pipe is idle and does not match the new format sp<NBAIO_Sink> teeSink; sp<NBAIO_Sink> teeSink; #ifdef TEE_SINK_INPUT_FRAMES enum { enum { TEE_SINK_NO, // don't copy input TEE_SINK_NO, // don't copy input TEE_SINK_NEW, // copy input using a new pipe TEE_SINK_NEW, // copy input using a new pipe Loading @@ -1610,7 +1634,9 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, } kind; } kind; NBAIO_Format format = Format_from_SR_C(inStream->common.get_sample_rate(&inStream->common), NBAIO_Format format = Format_from_SR_C(inStream->common.get_sample_rate(&inStream->common), popcount(inStream->common.get_channels(&inStream->common))); popcount(inStream->common.get_channels(&inStream->common))); if (format == Format_Invalid) { if (!mTeeSinkInputEnabled) { kind = TEE_SINK_NO; } else if (format == Format_Invalid) { kind = TEE_SINK_NO; kind = TEE_SINK_NO; } else if (mRecordTeeSink == 0) { } else if (mRecordTeeSink == 0) { kind = TEE_SINK_NEW; kind = TEE_SINK_NEW; Loading @@ -1623,7 +1649,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, } } switch (kind) { switch (kind) { case TEE_SINK_NEW: { case TEE_SINK_NEW: { Pipe *pipe = new Pipe(TEE_SINK_INPUT_FRAMES, format); Pipe *pipe = new Pipe(mTeeSinkInputFrames, format); size_t numCounterOffers = 0; size_t numCounterOffers = 0; const NBAIO_Format offers[1] = {format}; const NBAIO_Format offers[1] = {format}; ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers); ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers); Loading @@ -1644,7 +1670,7 @@ audio_io_handle_t AudioFlinger::openInput(audio_module_handle_t module, default: default: break; break; } } #endif AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream); AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream); // Start record thread // Start record thread Loading Loading @@ -2199,19 +2225,80 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId, return NO_ERROR; return NO_ERROR; } } struct Entry { #define MAX_NAME 32 // %Y%m%d%H%M%S_%d.wav char mName[MAX_NAME]; }; int comparEntry(const void *p1, const void *p2) { return strcmp(((const Entry *) p1)->mName, ((const Entry *) p2)->mName); } void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id) void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id) { { NBAIO_Source *teeSource = source.get(); NBAIO_Source *teeSource = source.get(); if (teeSource != NULL) { if (teeSource != NULL) { // .wav rotation // There is a benign race condition if 2 threads call this simultaneously. // They would both traverse the directory, but the result would simply be // failures at unlink() which are ignored. It's also unlikely since // normally dumpsys is only done by bugreport or from the command line. char teePath[32+256]; strcpy(teePath, "/data/misc/media"); size_t teePathLen = strlen(teePath); DIR *dir = opendir(teePath); teePath[teePathLen++] = '/'; if (dir != NULL) { #define MAX_SORT 20 // number of entries to sort #define MAX_KEEP 10 // number of entries to keep struct Entry entries[MAX_SORT]; size_t entryCount = 0; while (entryCount < MAX_SORT) { struct dirent de; struct dirent *result = NULL; int rc = readdir_r(dir, &de, &result); if (rc != 0) { ALOGW("readdir_r failed %d", rc); break; } if (result == NULL) { break; } if (result != &de) { ALOGW("readdir_r returned unexpected result %p != %p", result, &de); break; } // ignore non .wav file entries size_t nameLen = strlen(de.d_name); if (nameLen <= 4 || nameLen >= MAX_NAME || strcmp(&de.d_name[nameLen - 4], ".wav")) { continue; } strcpy(entries[entryCount++].mName, de.d_name); } (void) closedir(dir); if (entryCount > MAX_KEEP) { qsort(entries, entryCount, sizeof(Entry), comparEntry); for (size_t i = 0; i < entryCount - MAX_KEEP; ++i) { strcpy(&teePath[teePathLen], entries[i].mName); (void) unlink(teePath); } } } else { if (fd >= 0) { fdprintf(fd, "unable to rotate tees in %s: %s\n", teePath, strerror(errno)); } } char teeTime[16]; char teeTime[16]; struct timeval tv; struct timeval tv; gettimeofday(&tv, NULL); gettimeofday(&tv, NULL); struct tm tm; struct tm tm; localtime_r(&tv.tv_sec, &tm); localtime_r(&tv.tv_sec, &tm); strftime(teeTime, sizeof(teeTime), "%T", &tm); strftime(teeTime, sizeof(teeTime), "%Y%m%d%H%M%S", &tm); char teePath[64]; snprintf(&teePath[teePathLen], sizeof(teePath) - teePathLen, "%s_%d.wav", teeTime, id); sprintf(teePath, "/data/misc/media/%s_%d.wav", teeTime, id); // if 2 dumpsys are done within 1 second, and rotation didn't work, then discard 2nd int teeFd = open(teePath, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); int teeFd = open(teePath, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, S_IRUSR | S_IWUSR); if (teeFd >= 0) { if (teeFd >= 0) { char wavHeader[44]; char wavHeader[44]; memcpy(wavHeader, memcpy(wavHeader, Loading Loading @@ -2253,9 +2340,13 @@ void AudioFlinger::dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_hand temp = total * channelCount * sizeof(short); temp = total * channelCount * sizeof(short); write(teeFd, &temp, sizeof(temp)); write(teeFd, &temp, sizeof(temp)); close(teeFd); close(teeFd); fdprintf(fd, "FastMixer tee copied to %s\n", teePath); if (fd >= 0) { fdprintf(fd, "tee copied to %s\n", teePath); } } else { } else { fdprintf(fd, "FastMixer unable to create tee %s: \n", strerror(errno)); if (fd >= 0) { fdprintf(fd, "unable to create tee %s: %s\n", teePath, strerror(errno)); } } } } } } } Loading
services/audioflinger/AudioFlinger.h +17 −0 Original line number Original line Diff line number Diff line Loading @@ -593,7 +593,24 @@ private: sp<NBAIO_Source> mRecordTeeSource; sp<NBAIO_Source> mRecordTeeSource; public: public: // tee sink, if enabled by property, allows dumpsys to write most recent audio to .wav file static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id = 0); static void dumpTee(int fd, const sp<NBAIO_Source>& source, audio_io_handle_t id = 0); // whether tee sink is enabled by property static bool mTeeSinkInputEnabled; static bool mTeeSinkOutputEnabled; static bool mTeeSinkTrackEnabled; // runtime configured size of each tee sink pipe, in frames static size_t mTeeSinkInputFrames; static size_t mTeeSinkOutputFrames; static size_t mTeeSinkTrackFrames; // compile-time default size of tee sink pipes, in frames // 0x200000 stereo 16-bit PCM frames = 47.5 seconds at 44.1 kHz, 8 megabytes static const size_t kTeeSinkInputFramesDefault = 0x200000; static const size_t kTeeSinkOutputFramesDefault = 0x200000; static const size_t kTeeSinkTrackFramesDefault = 0x1000; }; }; #undef INCLUDING_FROM_AUDIOFLINGER_H #undef INCLUDING_FROM_AUDIOFLINGER_H Loading
services/audioflinger/Threads.cpp +13 −13 Original line number Original line Diff line number Diff line Loading @@ -2124,9 +2124,9 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud (monoPipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2); (monoPipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2); mPipeSink = monoPipe; mPipeSink = monoPipe; #ifdef TEE_SINK_FRAMES if (mTeeSinkOutputEnabled) { // create a Pipe to archive a copy of FastMixer's output for dumpsys // create a Pipe to archive a copy of FastMixer's output for dumpsys Pipe *teeSink = new Pipe(TEE_SINK_FRAMES, format); Pipe *teeSink = new Pipe(mTeeSinkOutputFrames, format); numCounterOffers = 0; numCounterOffers = 0; index = teeSink->negotiate(offers, 1, NULL, numCounterOffers); index = teeSink->negotiate(offers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); ALOG_ASSERT(index == 0); Loading @@ -2136,7 +2136,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud index = teeSource->negotiate(offers, 1, NULL, numCounterOffers); index = teeSource->negotiate(offers, 1, NULL, numCounterOffers); ALOG_ASSERT(index == 0); ALOG_ASSERT(index == 0); mTeeSource = teeSource; mTeeSource = teeSource; #endif } // create fast mixer and configure it initially with just one fast track for our submix // create fast mixer and configure it initially with just one fast track for our submix mFastMixer = new FastMixer(); mFastMixer = new FastMixer(); Loading
services/audioflinger/TrackBase.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -141,4 +141,7 @@ protected: Vector < sp<SyncEvent> >mSyncEvents; Vector < sp<SyncEvent> >mSyncEvents; const bool mIsOut; const bool mIsOut; ServerProxy* mServerProxy; ServerProxy* mServerProxy; const int mId; sp<NBAIO_Sink> mTeeSink; sp<NBAIO_Source> mTeeSource; }; };