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