13bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago/* 23bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * Copyright (C) 2016 The Android Open Source Project 33bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * 43bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * Licensed under the Apache License, Version 2.0 (the "License"); 53bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * you may not use this file except in compliance with the License. 63bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * You may obtain a copy of the License at 73bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * 83bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * http://www.apache.org/licenses/LICENSE-2.0 93bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * 103bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * Unless required by applicable law or agreed to in writing, software 113bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * distributed under the License is distributed on an "AS IS" BASIS, 123bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * See the License for the specific language governing permissions and 143bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago * limitations under the License. 153bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago */ 163bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 173bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 183bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago#include "BufLog.h" 193bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago#define LOG_TAG "BufLog" 203bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago//#define LOG_NDEBUG 0 213bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 223bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago#include <errno.h> 233bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago#include "log/log.h" 243bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago#include <pthread.h> 253bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago#include <stdio.h> 263bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago#include <string.h> 277e820c5cfdc8d9fd2f8c34ffe287f2479b6577d2Andy Hung#include <audio_utils/string.h> 283bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 293bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago#define MIN(a, b) ((a) < (b) ? (a) : (b)) 303bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 313bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago// ------------------------------ 323bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago// BufLogSingleton 333bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago// ------------------------------ 343bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragopthread_once_t onceControl = PTHREAD_ONCE_INIT; 353bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 363bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragoBufLog *BufLogSingleton::mInstance = NULL; 373bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 383bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragovoid BufLogSingleton::initOnce() { 393bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mInstance = new BufLog(); 403bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGW("=====================================\n" \ 413bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago "Warning: BUFLOG is defined in some part of your code.\n" \ 423bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago "This will create large audio dumps in %s.\n" \ 433bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago "=====================================\n", BUFLOG_BASE_PATH); 443bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 453bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 463bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragoBufLog *BufLogSingleton::instance() { 473bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago pthread_once(&onceControl, initOnce); 483bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago return mInstance; 493bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 503bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 513bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragobool BufLogSingleton::instanceExists() { 523bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago return mInstance != NULL; 533bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 543bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 553bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago// ------------------------------ 563bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago// BufLog 573bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago// ------------------------------ 583bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 593bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragoBufLog::BufLog() { 603bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago memset(mStreams, 0, sizeof(mStreams)); 613bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 623bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 633bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragoBufLog::~BufLog() { 643bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago android::Mutex::Autolock autoLock(mLock); 653bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 663bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago for (unsigned int id = 0; id < BUFLOG_MAXSTREAMS; id++) { 673bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago BufLogStream *pBLStream = mStreams[id]; 683bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (pBLStream != NULL) { 693bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago delete pBLStream ; 703bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mStreams[id] = NULL; 713bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 723bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 733bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 743bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 753bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragosize_t BufLog::write(int streamid, const char *tag, int format, int channels, 763bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago int samplingRate, size_t maxBytes, const void *buf, size_t size) { 773bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago unsigned int id = streamid % BUFLOG_MAXSTREAMS; 783bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago android::Mutex::Autolock autoLock(mLock); 793bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 803bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago BufLogStream *pBLStream = mStreams[id]; 813bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 823bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (pBLStream == NULL) { 833bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago pBLStream = mStreams[id] = new BufLogStream(id, tag, format, channels, 843bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago samplingRate, maxBytes); 853bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOG_ASSERT(pBLStream != NULL, "BufLogStream Failed to be created"); 863bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 873bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 883bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago return pBLStream->write(buf, size); 893bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 903bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 913bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragovoid BufLog::reset() { 923bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago android::Mutex::Autolock autoLock(mLock); 933bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGV("Resetting all BufLogs"); 943bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago int count = 0; 953bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 963bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago for (unsigned int id = 0; id < BUFLOG_MAXSTREAMS; id++) { 973bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago BufLogStream *pBLStream = mStreams[id]; 983bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (pBLStream != NULL) { 993bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago delete pBLStream; 1003bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mStreams[id] = NULL; 1013bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago count++; 1023bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 1033bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 1043bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGV("Reset %d BufLogs", count); 1053bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 1063bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1073bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago// ------------------------------ 1083bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago// BufLogStream 1093bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago// ------------------------------ 1103bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1113bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragoBufLogStream::BufLogStream(unsigned int id, 1123bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago const char *tag, 1133bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago unsigned int format, 1143bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago unsigned int channels, 1153bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago unsigned int samplingRate, 1163bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago size_t maxBytes = 0) : mId(id), mFormat(format), mChannels(channels), 1173bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mSamplingRate(samplingRate), mMaxBytes(maxBytes) { 1183bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mByteCount = 0l; 1193bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mPaused = false; 1203bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (tag != NULL) { 1217e820c5cfdc8d9fd2f8c34ffe287f2479b6577d2Andy Hung (void)audio_utils_strlcpy(mTag, tag); 1223bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } else { 1233bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mTag[0] = 0; 1243bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 12549f36ba3b4624ddd3d7efa34c95128a73bda6208Glenn Kasten ALOGV("Creating BufLogStream id:%d tag:%s format:%#x ch:%d sr:%d maxbytes:%zu", mId, mTag, 1263bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mFormat, mChannels, mSamplingRate, mMaxBytes); 1273bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1283bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago //open file (s), info about tag, format, etc. 1293bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago //timestamp 1303bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago char timeStr[16]; //size 16: format %Y%m%d%H%M%S 14 chars + string null terminator 1313bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago struct timeval tv; 1323bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago gettimeofday(&tv, NULL); 1333bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago struct tm tm; 1343bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago localtime_r(&tv.tv_sec, &tm); 1353bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago strftime(timeStr, sizeof(timeStr), "%Y%m%d%H%M%S", &tm); 1363bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago char logPath[BUFLOG_MAX_PATH_SIZE]; 1373bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago snprintf(logPath, BUFLOG_MAX_PATH_SIZE, "%s/%s_%d_%s_%d_%d_%d.raw", BUFLOG_BASE_PATH, timeStr, 1383bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mId, mTag, mFormat, mChannels, mSamplingRate); 1393bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGV("data output: %s", logPath); 1403bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1413bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mFile = fopen(logPath, "wb"); 1423bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (mFile != NULL) { 1433bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGV("Success creating file at: %p", mFile); 1443bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } else { 1453bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGE("Error: could not create file BufLogStream %s", strerror(errno)); 1463bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 1473bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 1483bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1493bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragovoid BufLogStream::closeStream_l() { 1503bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGV("Closing BufLogStream id:%d tag:%s", mId, mTag); 1513bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (mFile != NULL) { 1523bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago fclose(mFile); 1533bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mFile = NULL; 1543bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 1553bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 1563bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1573bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragoBufLogStream::~BufLogStream() { 1583bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGV("Destroying BufLogStream id:%d tag:%s", mId, mTag); 1593bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago android::Mutex::Autolock autoLock(mLock); 1603bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago closeStream_l(); 1613bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 1623bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1633bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragosize_t BufLogStream::write(const void *buf, size_t size) { 1643bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1653bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago size_t bytes = 0; 1663bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (!mPaused && mFile != NULL) { 1673bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (size > 0 && buf != NULL) { 1683bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago android::Mutex::Autolock autoLock(mLock); 1693bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (mMaxBytes > 0) { 1703bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago size = MIN(size, mMaxBytes - mByteCount); 1713bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 1723bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago bytes = fwrite(buf, 1, size, mFile); 1733bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mByteCount += bytes; 1743bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago if (mMaxBytes > 0 && mMaxBytes == mByteCount) { 1753bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago closeStream_l(); 1763bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 1773bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 1783bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGV("wrote %zu/%zu bytes to BufLogStream %d tag:%s. Total Bytes: %zu", bytes, size, mId, 1793bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mTag, mByteCount); 1803bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } else { 1813bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago ALOGV("Warning: trying to write to %s BufLogStream id:%d tag:%s", 1823bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mPaused ? "paused" : "closed", mId, mTag); 1833bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago } 1843bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago return bytes; 1853bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 1863bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1873bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragobool BufLogStream::setPause(bool pause) { 1883bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago bool old = mPaused; 1893bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago mPaused = pause; 1903bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago return old; 1913bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 1923bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago 1933bd1c87ac0d767566f5da387e90b8a3cd86ecc97ragovoid BufLogStream::finalize() { 1943bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago android::Mutex::Autolock autoLock(mLock); 1953bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago closeStream_l(); 1963bd1c87ac0d767566f5da387e90b8a3cd86ecc97rago} 197