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