• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 #include "BufLog.h"
19 #define LOG_TAG "BufLog"
20 //#define LOG_NDEBUG 0
21 
22 #include <errno.h>
23 #include "log/log.h"
24 #include <pthread.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <audio_utils/string.h>
28 
29 #define MIN(a, b) ((a) < (b) ? (a) : (b))
30 
31 namespace android {
32 
33 // ------------------------------
34 // BufLogSingleton
35 // ------------------------------
36 pthread_once_t onceControl = PTHREAD_ONCE_INIT;
37 
38 BufLog *BufLogSingleton::mInstance = nullptr;
39 
initOnce()40 void BufLogSingleton::initOnce() {
41     mInstance = new BufLog();
42     ALOGW("=====================================\n" \
43             "Warning: BUFLOG is defined in some part of your code.\n" \
44             "This will create large audio dumps in %s.\n" \
45             "=====================================\n", BUFLOG_BASE_PATH);
46 }
47 
instance()48 BufLog *BufLogSingleton::instance() {
49     pthread_once(&onceControl, initOnce);
50     return mInstance;
51 }
52 
instanceExists()53 bool BufLogSingleton::instanceExists() {
54     return mInstance != nullptr;
55 }
56 
57 // ------------------------------
58 // BufLog
59 // ------------------------------
60 
~BufLog()61 BufLog::~BufLog() {
62     reset();
63 }
64 
write(int streamid,const char * tag,int format,int channels,int samplingRate,size_t maxBytes,const void * buf,size_t size)65 size_t BufLog::write(int streamid, const char *tag, int format, int channels,
66         int samplingRate, size_t maxBytes, const void *buf, size_t size) {
67     const unsigned int id = streamid % BUFLOG_MAXSTREAMS;
68     const std::lock_guard autoLock(mLock);
69 
70     BufLogStream *pBLStream = mStreams[id];
71 
72     if (pBLStream == nullptr) {
73         pBLStream = mStreams[id] = new BufLogStream(id, tag, format, channels,
74                 samplingRate, maxBytes);
75     }
76 
77     return pBLStream->write(buf, size);
78 }
79 
reset()80 void BufLog::reset() {
81     const std::lock_guard autoLock(mLock);
82     int count = 0;
83     for (auto &pBLStream : mStreams) {
84         if (pBLStream != nullptr) {
85             delete pBLStream;
86             pBLStream = nullptr;
87             count++;
88         }
89     }
90     ALOGV("Reset %d BufLogs", count);
91 }
92 
93 // ------------------------------
94 // BufLogStream
95 // ------------------------------
96 
BufLogStream(unsigned int id,const char * tag,unsigned int format,unsigned int channels,unsigned int samplingRate,size_t maxBytes=0)97 BufLogStream::BufLogStream(unsigned int id,
98         const char *tag,
99         unsigned int format,
100         unsigned int channels,
101         unsigned int samplingRate,
102         size_t maxBytes = 0) : mId(id), mFormat(format), mChannels(channels),
103                 mSamplingRate(samplingRate), mMaxBytes(maxBytes) {
104     if (tag != nullptr) {
105         (void)audio_utils_strlcpy(mTag, tag);
106     } else {
107         mTag[0] = 0;
108     }
109     ALOGV("Creating BufLogStream id:%d tag:%s format:%#x ch:%d sr:%d maxbytes:%zu", mId, mTag,
110             mFormat, mChannels, mSamplingRate, mMaxBytes);
111 
112     //open file (s), info about tag, format, etc.
113     //timestamp
114     char timeStr[16];   //size 16: format %Y%m%d%H%M%S 14 chars + string null terminator
115     struct timeval tv;
116     gettimeofday(&tv, nullptr);
117     struct tm tm;
118     localtime_r(&tv.tv_sec, &tm);
119     strftime(timeStr, sizeof(timeStr), "%Y%m%d%H%M%S", &tm);
120     char logPath[BUFLOG_MAX_PATH_SIZE];
121     snprintf(logPath, BUFLOG_MAX_PATH_SIZE, "%s/%s_%d_%s_%d_%d_%d.raw", BUFLOG_BASE_PATH, timeStr,
122             mId, mTag, mFormat, mChannels, mSamplingRate);
123     ALOGV("data output: %s", logPath);
124 
125     mFile = fopen(logPath, "wb");
126     if (mFile != nullptr) {
127         ALOGV("Success creating file at: %p", mFile);
128     } else {
129         ALOGE("Error: could not create file BufLogStream %s", strerror(errno));
130     }
131 }
132 
closeStream_l()133 void BufLogStream::closeStream_l() {
134     ALOGV("Closing BufLogStream id:%d tag:%s", mId, mTag);
135     if (mFile != nullptr) {
136         fclose(mFile);
137         mFile = nullptr;
138     }
139 }
140 
~BufLogStream()141 BufLogStream::~BufLogStream() {
142     ALOGV("Destroying BufLogStream id:%d tag:%s", mId, mTag);
143     const std::lock_guard autoLock(mLock);
144     closeStream_l();
145 }
146 
write(const void * buf,size_t size)147 size_t BufLogStream::write(const void *buf, size_t size) {
148 
149     size_t bytes = 0;
150     if (!mPaused && mFile != nullptr) {
151         if (size > 0 && buf != nullptr) {
152             const std::lock_guard autoLock(mLock);
153             if (mMaxBytes > 0) {
154                 size = MIN(size, mMaxBytes - mByteCount);
155             }
156             bytes = fwrite(buf, 1, size, mFile);
157             mByteCount += bytes;
158             if (mMaxBytes > 0 && mMaxBytes == mByteCount) {
159                 closeStream_l();
160             }
161         }
162         ALOGV("wrote %zu/%zu bytes to BufLogStream %d tag:%s. Total Bytes: %zu", bytes, size, mId,
163                 mTag, mByteCount);
164     } else {
165         ALOGV("Warning: trying to write to %s BufLogStream id:%d tag:%s",
166                 mPaused ? "paused" : "closed", mId, mTag);
167     }
168     return bytes;
169 }
170 
setPause(bool pause)171 bool BufLogStream::setPause(bool pause) {
172     const bool old = mPaused;
173     mPaused = pause;
174     return old;
175 }
176 
finalize()177 void BufLogStream::finalize() {
178     const std::lock_guard autoLock(mLock);
179     closeStream_l();
180 }
181 
182 } // namespace android
183