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