1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ANDROID_AUDIO_BUFLOG_H
18#define ANDROID_AUDIO_BUFLOG_H
19
20/*
21 * BUFLOG creates up to BUFLOG_MAXSTREAMS simultaneous streams [0:15] of audio buffer data
22 * and saves them to disk. The files are stored in the path specified in BUFLOG_BASE_PATH and
23 * are named following this format:
24 *   YYYYMMDDHHMMSS_id_format_channels_samplingrate.raw
25 *
26 * Normally we strip BUFLOG dumps from release builds.
27 * You can modify this (for example with "#define BUFLOG_NDEBUG 0"
28 * at the top of your source file) to change that behavior.
29 *
30 * usage:
31 * - Add this to the top of the source file you want to debug:
32 *   #define BUFLOG_NDEBUG 0
33 *   #include "BufLog.h"
34 *
35 * - dump an audio buffer
36 *  BUFLOG(buff_id, buff_tag, format, channels, sampling_rate, max_bytes, buff_pointer, buff_size);
37 *
38 *  buff_id:   int [0:15]   buffer id. If a buffer doesn't exist, it is created the first time.
39 *  buff_tag:  char*        string tag used on stream filename and logs
40 *  format:    int          Audio format (audio_format_t see audio.h)
41 *  channels:  int          Channel Count
42 *  sampling_rate:  int     Sampling rate in Hz. e.g. 8000, 16000, 44100, 48000, etc
43 *  max_bytes: int [0 or positive number]
44 *                          Maximum size of the file (in bytes) to be output.
45 *                          If the value is 0, no limit.
46 *  buff_pointer: void *    Pointer to audio buffer.
47 *  buff_size:  int         Size (in bytes) of the current audio buffer to be stored.
48 *
49 *
50 *  Example usage:
51 *    int format       = mConfig.outputCfg.format;
52 *    int channels     = audio_channel_count_from_out_mask(mConfig.outputCfg.channels);
53 *    int samplingRate = mConfig.outputCfg.samplingRate;
54 *    int frameCount   = mConfig.outputCfg.buffer.frameCount;
55 *    int frameSize    = audio_bytes_per_sample((audio_format_t)format) * channels;
56 *    int buffSize     = frameCount * frameSize;
57 *    long maxBytes = 10 * samplingRate * frameSize; //10 seconds max
58 *  BUFLOG(11, "loudnes_enhancer_out", format, channels, samplingRate, maxBytes,
59 *                               mConfig.outputCfg.buffer.raw, buffSize);
60 *
61 *  Other macros:
62 *  BUFLOG_EXISTS       returns true if there is an instance of BufLog
63 *
64 *  BUFLOG_RESET        If an instance of BufLog exists, it stops the capture and closes all
65 *                      streams.
66 *                      If a new call to BUFLOG(..) is done, new streams are created.
67 */
68
69#ifndef BUFLOG_NDEBUG
70#ifdef NDEBUG
71#define BUFLOG_NDEBUG 1
72#else
73#define BUFLOG_NDEBUG 0
74#endif
75#endif
76
77/*
78 * Simplified macro to send a buffer.
79 */
80#ifndef BUFLOG
81#define __BUFLOG(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, BUF, SIZE) \
82    BufLogSingleton::instance()->write(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, \
83            BUF, SIZE)
84#if BUFLOG_NDEBUG
85#define BUFLOG(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, BUF, SIZE) \
86    do { if (0) {  } } while (0)
87#else
88#define BUFLOG(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, BUF, SIZE) \
89    __BUFLOG(STREAMID, TAG, FORMAT, CHANNELS, SAMPLINGRATE, MAXBYTES, BUF, SIZE)
90#endif
91#endif
92
93#ifndef BUFLOG_EXISTS
94#define BUFLOG_EXISTS BufLogSingleton::instanceExists()
95#endif
96
97#ifndef BUFLOG_RESET
98#define BUFLOG_RESET do { if (BufLogSingleton::instanceExists()) { \
99    BufLogSingleton::instance()->reset(); } } while (0)
100#endif
101
102
103#include <stdint.h>
104#include <stdio.h>
105#include <sys/types.h>
106#include <utils/Mutex.h>
107
108//BufLog configuration
109#define BUFLOGSTREAM_MAX_TAGSIZE    32
110#define BUFLOG_BASE_PATH            "/data/misc/audioserver"
111#define BUFLOG_MAX_PATH_SIZE        300
112
113class BufLogStream {
114public:
115    BufLogStream(unsigned int id,
116            const char *tag,
117            unsigned int format,
118            unsigned int channels,
119            unsigned int samplingRate,
120            size_t maxBytes);
121    ~BufLogStream();
122
123    // write buffer to stream
124    //  buf:  pointer to buffer
125    //  size: number of bytes to write
126    size_t          write(const void *buf, size_t size);
127
128    // pause/resume stream
129    //  pause: true = paused, false = not paused
130    //  return value: previous state of stream (paused or not).
131    bool            setPause(bool pause);
132
133    // will stop the stream and close any open file
134    // the stream can't be reopen. Instead, a new stream (and file) should be created.
135    void            finalize();
136
137private:
138    bool                mPaused;
139    const unsigned int  mId;
140    char                mTag[BUFLOGSTREAM_MAX_TAGSIZE + 1];
141    const unsigned int  mFormat;
142    const unsigned int  mChannels;
143    const unsigned int  mSamplingRate;
144    const size_t        mMaxBytes;
145    size_t              mByteCount;
146    FILE                *mFile;
147    mutable android::Mutex mLock;
148
149    void            closeStream_l();
150};
151
152
153class BufLog {
154public:
155    BufLog();
156    ~BufLog();
157    BufLog(BufLog const&) {};
158
159    //  streamid:      int [0:BUFLOG_MAXSTREAMS-1]   buffer id.
160    //                  If a buffer doesn't exist, it is created the first time is referenced
161    //  tag:           char*  string tag used on stream filename and logs
162    //  format:        int Audio format (audio_format_t see audio.h)
163    //  channels:      int          Channel Count
164    //  samplingRate:  int Sampling rate in Hz. e.g. 8000, 16000, 44100, 48000, etc
165    //  maxBytes:      int [0 or positive number]
166    //                  Maximum size of the file (in bytes) to be output.
167    //                  If the value is 0, no limit.
168    //  size:          int Size (in bytes) of the current audio buffer to be written.
169    //  buf:           void *    Pointer to audio buffer.
170    size_t          write(int streamid,
171                        const char *tag,
172                        int format,
173                        int channels,
174                        int samplingRate,
175                        size_t maxBytes,
176                        const void *buf,
177                        size_t size);
178
179    // reset will stop and close all active streams, thus finalizing any open file.
180    //  New streams will be created if write() is called again.
181    void            reset();
182
183protected:
184    static const unsigned int BUFLOG_MAXSTREAMS = 16;
185    BufLogStream    *mStreams[BUFLOG_MAXSTREAMS];
186    mutable android::Mutex mLock;
187};
188
189class BufLogSingleton {
190public:
191    static BufLog   *instance();
192    static bool     instanceExists();
193
194private:
195    static void     initOnce();
196    static BufLog   *mInstance;
197};
198
199#endif //ANDROID_AUDIO_BUFLOG_H
200