• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "MidiIoWrapper"
19 #include <utils/Log.h>
20 
21 #include <fcntl.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #include <algorithm>
25 
26 #include <media/MidiIoWrapper.h>
27 #include <media/MediaExtractorPluginApi.h>
28 
readAt(void * handle,void * buffer,int pos,int size)29 static int readAt(void *handle, void *buffer, int pos, int size) {
30     return ((android::MidiIoWrapper*)handle)->readAt(buffer, pos, size);
31 }
size(void * handle)32 static int size(void *handle) {
33     return ((android::MidiIoWrapper*)handle)->size();
34 }
35 
36 namespace android {
37 int MidiIoWrapper::sCacheBufferSize = 0;
38 Mutex MidiIoWrapper::mCacheLock;
39 
MidiIoWrapper(const char * path)40 MidiIoWrapper::MidiIoWrapper(const char *path) {
41     ALOGV("MidiIoWrapper(%s)", path);
42     mFd = open(path, O_RDONLY | O_LARGEFILE);
43     mBase = 0;
44     mLength = lseek(mFd, 0, SEEK_END);
45     mDataSource = nullptr;
46     mCacheBuffer = NULL;
47     mCacheBufRangeLength = 0;
48 }
49 
MidiIoWrapper(int fd,off64_t offset,int64_t size)50 MidiIoWrapper::MidiIoWrapper(int fd, off64_t offset, int64_t size) {
51     ALOGV("MidiIoWrapper(fd=%d)", fd);
52     mFd = fd < 0 ? -1 : dup(fd);
53     mBase = offset;
54     mLength = size;
55     mDataSource = nullptr;
56     mCacheBuffer = NULL;
57     mCacheBufRangeLength = 0;
58 }
59 
60 class MidiIoWrapper::DataSourceUnwrapper {
61 
62 public:
DataSourceUnwrapper(CDataSource * csource)63     explicit DataSourceUnwrapper(CDataSource *csource) {
64         mSource = csource;
65     }
66 
~DataSourceUnwrapper()67     virtual ~DataSourceUnwrapper() {}
68 
initCheck() const69     virtual status_t initCheck() const { return OK; }
70 
71     // Returns the number of bytes read, or -1 on failure. It's not an error if
72     // this returns zero; it just means the given offset is equal to, or
73     // beyond, the end of the source.
readAt(off64_t offset,void * data,size_t size)74     virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
75         return mSource->readAt(mSource->handle, offset, data, size);
76     }
77 
78     // May return ERROR_UNSUPPORTED.
getSize(off64_t * size)79     virtual status_t getSize(off64_t *size) {
80         return mSource->getSize(mSource->handle, size);
81     }
82 
getUri(char *,size_t)83     virtual bool getUri(char * /*uriString*/, size_t /*bufferSize*/) {
84         return false;
85     }
86 
flags()87     virtual uint32_t flags() {
88         return 0;
89     }
90 
close()91     virtual void close() {};
92 private:
93     CDataSource *mSource;
94 };
95 
MidiIoWrapper(CDataSource * csource)96 MidiIoWrapper::MidiIoWrapper(CDataSource *csource) {
97     ALOGV("MidiIoWrapper(CDataSource)");
98     mFd = -1;
99     mBase = 0;
100     mDataSource = new DataSourceUnwrapper(csource);
101     off64_t l;
102     if (mDataSource->getSize(&l) == OK) {
103         mLength = l;
104     } else {
105         mLength = 0;
106     }
107     mCacheBuffer = NULL;
108     mCacheBufRangeLength = 0;
109 }
110 
~MidiIoWrapper()111 MidiIoWrapper::~MidiIoWrapper() {
112     ALOGV("~MidiIoWrapper");
113     if (mFd >= 0) {
114         close(mFd);
115     }
116     delete mDataSource;
117 
118     if (NULL != mCacheBuffer) {
119         delete [] mCacheBuffer;
120         mCacheBuffer = NULL;
121         {
122             Mutex::Autolock _l(mCacheLock);
123             sCacheBufferSize -= mLength;
124         }
125     }
126 }
127 
readAt(void * buffer,int offset,int size)128 int MidiIoWrapper::readAt(void *buffer, int offset, int size) {
129     ALOGV("readAt(%p, %d, %d)", buffer, offset, size);
130 
131     if (offset < 0) {
132         return UNKNOWN_ERROR;
133     }
134 
135     if (offset + size > mLength) {
136         size = mLength - offset;
137     }
138 
139     if (mCacheBuffer == NULL) {
140         Mutex::Autolock _l(mCacheLock);
141         if (sCacheBufferSize + mLength <= kTotalCacheSize) {
142             mCacheBuffer = new (std::nothrow) unsigned char[mLength];
143             if (NULL != mCacheBuffer) {
144                 sCacheBufferSize += mLength;
145                 ALOGV("sCacheBufferSize : %d", sCacheBufferSize);
146             } else {
147                 ALOGE("failed to allocate memory for mCacheBuffer");
148             }
149         } else {
150             ALOGV("not allocate memory for mCacheBuffer");
151         }
152     }
153 
154     if (mCacheBuffer != NULL) {
155         if (mCacheBufRangeLength > 0 && mCacheBufRangeLength >= (offset + size)) {
156             /* Use buffered data */
157             memcpy(buffer, (void*)(mCacheBuffer + offset), size);
158             return size;
159         } else {
160             /* Buffer new data */
161             int64_t beyondCacheBufRangeLength = (offset + size) - mCacheBufRangeLength;
162             int64_t numRequiredBytesToCache =
163                   std::max((int64_t)kSingleCacheSize, beyondCacheBufRangeLength);
164             int64_t availableReadLength = mLength - mCacheBufRangeLength;
165             int64_t readSize = std::min(availableReadLength, numRequiredBytesToCache);
166             int actualNumBytesRead =
167                 unbufferedReadAt(mCacheBuffer + mCacheBufRangeLength,
168                         mCacheBufRangeLength, readSize);
169             if(actualNumBytesRead > 0) {
170                 mCacheBufRangeLength += actualNumBytesRead;
171                 if (offset >= mCacheBufRangeLength) {
172                     return 0;
173                 } else if (offset + size >= mCacheBufRangeLength) {
174                     memcpy(buffer, (void*)(mCacheBuffer + offset), mCacheBufRangeLength - offset);
175                     return mCacheBufRangeLength - offset;
176                 } else {
177                     memcpy(buffer, (void*)(mCacheBuffer + offset), size);
178                     return size;
179                 }
180             } else {
181                 return actualNumBytesRead;
182             }
183         }
184     } else {
185         return unbufferedReadAt(buffer, offset, size);
186     }
187 }
188 
unbufferedReadAt(void * buffer,int offset,int size)189 int MidiIoWrapper::unbufferedReadAt(void *buffer, int offset, int size) {
190     ALOGV("unbufferedReadAt(%p, %d, %d)", buffer, offset, size);
191     if (mDataSource != NULL) {
192         return mDataSource->readAt(offset, buffer, size);
193     }
194     if (mFd < 0) {
195         errno = EBADF;
196         return -1; // as per failed read.
197     }
198     lseek(mFd, mBase + offset, SEEK_SET);
199     if (offset + size > mLength) {
200         size = mLength - offset;
201     }
202     return read(mFd, buffer, size);
203 }
204 
size()205 int MidiIoWrapper::size() {
206     ALOGV("size() = %d", int(mLength));
207     return mLength;
208 }
209 
getLocator()210 EAS_FILE_LOCATOR MidiIoWrapper::getLocator() {
211     mEasFile.handle = this;
212     mEasFile.readAt = ::readAt;
213     mEasFile.size = ::size;
214     return &mEasFile;
215 }
216 
217 }  // namespace android
218