/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_AUDIO_BUFLOG_H #define ANDROID_AUDIO_BUFLOG_H /* * BUFLOG creates up to BUFLOG_MAXSTREAMS simultaneous streams [0:15] of audio buffer data * and saves them to disk. The files are stored in the path specified in BUFLOG_BASE_PATH and * are named following this format: * YYYYMMDDHHMMSS_id_format_channels_samplingrate.raw * * Normally we strip BUFLOG dumps from release builds. * You can modify this (for example with "#define BUFLOG_NDEBUG 0" * at the top of your source file) to change that behavior. * * usage: * - Add this to the top of the source file you want to debug: * #define BUFLOG_NDEBUG 0 * #include "BufLog.h" * * - dump an audio buffer * BUFLOG(buff_id, buff_tag, format, channels, sampling_rate, max_bytes, buff_pointer, buff_size); * * buff_id: int [0:15] buffer id. If a buffer doesn't exist, it is created the first time. * buff_tag: char* string tag used on stream filename and logs * format: int Audio format (audio_format_t see audio.h) * channels: int Channel Count * sampling_rate: int Sampling rate in Hz. e.g. 8000, 16000, 44100, 48000, etc * max_bytes: int [0 or positive number] * Maximum size of the file (in bytes) to be output. * If the value is 0, no limit. * buff_pointer: void * Pointer to audio buffer. * buff_size: int Size (in bytes) of the current audio buffer to be stored. * * * Example usage: * int format = mConfig.outputCfg.format; * int channels = audio_channel_count_from_out_mask(mConfig.outputCfg.channels); * int samplingRate = mConfig.outputCfg.samplingRate; * int frameCount = mConfig.outputCfg.buffer.frameCount; * int frameSize = audio_bytes_per_sample((audio_format_t)format) * channels; * int buffSize = frameCount * frameSize; * long maxBytes = 10 * samplingRate * frameSize; //10 seconds max * BUFLOG(11, "loudnes_enhancer_out", format, channels, samplingRate, maxBytes, * mConfig.outputCfg.buffer.raw, buffSize); * * Other macros: * BUFLOG_EXISTS returns true if there is an instance of BufLog * * BUFLOG_RESET If an instance of BufLog exists, it stops the capture and closes all * streams. * If a new call to BUFLOG(..) is done, new streams are created. */ #ifndef BUFLOG_NDEBUG #ifdef NDEBUG #define BUFLOG_NDEBUG 1 #else #define BUFLOG_NDEBUG 0 #endif #endif /* * Simplified macro to send a buffer. */ #ifndef BUFLOG #define __BUFLOG(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, BUF, SIZE) \ BufLogSingleton::instance()->write(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, \ BUF, SIZE) #if BUFLOG_NDEBUG #define BUFLOG(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, BUF, SIZE) \ do { if (0) { } } while (0) #else #define BUFLOG(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, BUF, SIZE) \ __BUFLOG(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, BUF, SIZE) #endif #endif #ifndef BUFLOG_EXISTS #define BUFLOG_EXISTS BufLogSingleton::instanceExists() #endif #ifndef BUFLOG_RESET #define BUFLOG_RESET do { if (BufLogSingleton::instanceExists()) { \ BufLogSingleton::instance()->reset(); } } while (0) #endif #include #include #include #include //BufLog configuration #define BUFLOGSTREAM_MAX_TAGSIZE 32 #define BUFLOG_BASE_PATH "/data/misc/audioserver" #define BUFLOG_MAX_PATH_SIZE 300 class BufLogStream { public: BufLogStream(unsigned int id, const char *tag, unsigned int format, unsigned int channels, unsigned int samplingRate, size_t maxBytes); ~BufLogStream(); // write buffer to stream // buf: pointer to buffer // size: number of bytes to write size_t write(const void *buf, size_t size); // pause/resume stream // pause: true = paused, false = not paused // return value: previous state of stream (paused or not). bool setPause(bool pause); // will stop the stream and close any open file // the stream can't be reopen. Instead, a new stream (and file) should be created. void finalize(); private: bool mPaused; const unsigned int mId; char mTag[BUFLOGSTREAM_MAX_TAGSIZE + 1]; const unsigned int mFormat; const unsigned int mChannels; const unsigned int mSamplingRate; const size_t mMaxBytes; size_t mByteCount; FILE *mFile; mutable android::Mutex mLock; void closeStream_l(); }; class BufLog { public: BufLog(); ~BufLog(); BufLog(BufLog const&) {}; // streamid: int [0:BUFLOG_MAXSTREAMS-1] buffer id. // If a buffer doesn't exist, it is created the first time is referenced // tag: char* string tag used on stream filename and logs // format: int Audio format (audio_format_t see audio.h) // channels: int Channel Count // samplingRate: int Sampling rate in Hz. e.g. 8000, 16000, 44100, 48000, etc // maxBytes: int [0 or positive number] // Maximum size of the file (in bytes) to be output. // If the value is 0, no limit. // size: int Size (in bytes) of the current audio buffer to be written. // buf: void * Pointer to audio buffer. size_t write(int streamid, const char *tag, int format, int channels, int samplingRate, size_t maxBytes, const void *buf, size_t size); // reset will stop and close all active streams, thus finalizing any open file. // New streams will be created if write() is called again. void reset(); protected: static const unsigned int BUFLOG_MAXSTREAMS = 16; BufLogStream *mStreams[BUFLOG_MAXSTREAMS]; mutable android::Mutex mLock; }; class BufLogSingleton { public: static BufLog *instance(); static bool instanceExists(); private: static void initOnce(); static BufLog *mInstance; }; #endif //ANDROID_AUDIO_BUFLOG_H