Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2012 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 | #ifndef ANDROID_AUDIO_NBAIO_H |
| 18 | #define ANDROID_AUDIO_NBAIO_H |
| 19 | |
| 20 | // Non-blocking audio I/O interface |
| 21 | // |
| 22 | // This header file has the abstract interfaces only. Concrete implementation classes are declared |
| 23 | // elsewhere. Implementations _should_ be non-blocking for all methods, especially read() and |
| 24 | // write(), but this is not enforced. In general, implementations do not need to be multi-thread |
| 25 | // safe, and any exceptions are noted in the particular implementation. |
| 26 | |
| 27 | #include <limits.h> |
| 28 | #include <stdlib.h> |
John Grossman | 2c3b2da | 2012-08-02 17:08:54 -0700 | [diff] [blame] | 29 | #include <utils/Errors.h> |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 30 | #include <utils/RefBase.h> |
Glenn Kasten | 767094d | 2013-08-23 13:51:43 -0700 | [diff] [blame] | 31 | #include <media/AudioTimestamp.h> |
Glenn Kasten | f95a3c4 | 2014-03-06 07:59:49 -0800 | [diff] [blame^] | 32 | #include <system/audio.h> |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 33 | |
| 34 | namespace android { |
| 35 | |
| 36 | // In addition to the usual status_t |
| 37 | enum { |
| 38 | NEGOTIATE = 0x80000010, // Must (re-)negotiate format. For negotiate() only, the offeree |
| 39 | // doesn't accept offers, and proposes counter-offers |
| 40 | OVERRUN = 0x80000011, // availableToRead(), read(), or readVia() detected lost input due |
| 41 | // to overrun; an event is counted and the caller should re-try |
| 42 | UNDERRUN = 0x80000012, // availableToWrite(), write(), or writeVia() detected a gap in |
| 43 | // output due to underrun (not being called often enough, or with |
| 44 | // enough data); an event is counted and the caller should re-try |
| 45 | }; |
| 46 | |
| 47 | // Negotiation of format is based on the data provider and data sink, or the data consumer and |
| 48 | // data source, exchanging prioritized arrays of offers and counter-offers until a single offer is |
| 49 | // mutually agreed upon. Each offer is an NBAIO_Format. For simplicity and performance, |
Glenn Kasten | b64497e | 2012-10-01 09:47:30 -0700 | [diff] [blame] | 50 | // NBAIO_Format is a typedef that ties together the most important combinations of the various |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 51 | // attributes, rather than a struct with separate fields for format, sample rate, channel count, |
| 52 | // interleave, packing, alignment, etc. The reason is that NBAIO_Format tries to abstract out only |
Glenn Kasten | b64497e | 2012-10-01 09:47:30 -0700 | [diff] [blame] | 53 | // the combinations that are actually needed within AudioFlinger. If the list of combinations grows |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 54 | // too large, then this decision should be re-visited. |
Glenn Kasten | b64497e | 2012-10-01 09:47:30 -0700 | [diff] [blame] | 55 | // Sample rate and channel count are explicit, PCM interleaved 16-bit is assumed. |
Glenn Kasten | c4b8b32 | 2014-01-31 09:39:01 -0800 | [diff] [blame] | 56 | struct NBAIO_Format { |
| 57 | //private: |
| 58 | unsigned mPacked; |
| 59 | }; |
Glenn Kasten | 51d53cd | 2014-01-31 09:38:33 -0800 | [diff] [blame] | 60 | |
| 61 | extern const NBAIO_Format Format_Invalid; |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 62 | |
| 63 | // Return the frame size of an NBAIO_Format in bytes |
Glenn Kasten | 72e54af | 2014-01-31 09:37:35 -0800 | [diff] [blame] | 64 | size_t Format_frameSize(const NBAIO_Format& format); |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 65 | |
| 66 | // Return the frame size of an NBAIO_Format as a bit shift |
Glenn Kasten | 4d7b3f8 | 2014-01-31 10:38:16 -0800 | [diff] [blame] | 67 | // or -1 if frame size is not a power of 2 |
| 68 | int Format_frameBitShift(const NBAIO_Format& format); |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 69 | |
| 70 | // Convert a sample rate in Hz and channel count to an NBAIO_Format |
Glenn Kasten | f95a3c4 | 2014-03-06 07:59:49 -0800 | [diff] [blame^] | 71 | // FIXME Remove the default value of AUDIO_FORMAT_PCM_16_BIT, and rename |
| 72 | NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount, |
| 73 | audio_format_t format = AUDIO_FORMAT_PCM_16_BIT); |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 74 | |
| 75 | // Return the sample rate in Hz of an NBAIO_Format |
Glenn Kasten | 72e54af | 2014-01-31 09:37:35 -0800 | [diff] [blame] | 76 | unsigned Format_sampleRate(const NBAIO_Format& format); |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 77 | |
| 78 | // Return the channel count of an NBAIO_Format |
Glenn Kasten | 72e54af | 2014-01-31 09:37:35 -0800 | [diff] [blame] | 79 | unsigned Format_channelCount(const NBAIO_Format& format); |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 80 | |
| 81 | // Callbacks used by NBAIO_Sink::writeVia() and NBAIO_Source::readVia() below. |
| 82 | typedef ssize_t (*writeVia_t)(void *user, void *buffer, size_t count); |
John Grossman | 2c3b2da | 2012-08-02 17:08:54 -0700 | [diff] [blame] | 83 | typedef ssize_t (*readVia_t)(void *user, const void *buffer, |
| 84 | size_t count, int64_t readPTS); |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 85 | |
Glenn Kasten | cc1e0e8 | 2014-01-31 09:48:42 -0800 | [diff] [blame] | 86 | // Check whether an NBAIO_Format is valid |
| 87 | bool Format_isValid(const NBAIO_Format& format); |
| 88 | |
| 89 | // Compare two NBAIO_Format values |
| 90 | bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2); |
| 91 | |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 92 | // Abstract class (interface) representing a data port. |
| 93 | class NBAIO_Port : public RefBase { |
| 94 | |
| 95 | public: |
| 96 | |
| 97 | // negotiate() must called first. The purpose of negotiate() is to check compatibility of |
| 98 | // formats, not to automatically adapt if they are incompatible. It's the responsibility of |
| 99 | // whoever sets up the graph connections to make sure formats are compatible, and this method |
| 100 | // just verifies that. The edges are "dumb" and don't attempt to adapt to bad connections. |
| 101 | // How it works: offerer proposes an array of formats, in descending order of preference from |
| 102 | // offers[0] to offers[numOffers - 1]. If offeree accepts one of these formats, it returns |
| 103 | // the index of that offer. Otherwise, offeree sets numCounterOffers to the number of |
| 104 | // counter-offers (up to a maximumum of the entry value of numCounterOffers), fills in the |
| 105 | // provided array counterOffers[] with its counter-offers, in descending order of preference |
| 106 | // from counterOffers[0] to counterOffers[numCounterOffers - 1], and returns NEGOTIATE. |
| 107 | // Note that since the offerer allocates space for counter-offers, but only the offeree knows |
| 108 | // how many counter-offers it has, there may be insufficient space for all counter-offers. |
| 109 | // In that case, the offeree sets numCounterOffers to the requested number of counter-offers |
| 110 | // (which is greater than the entry value of numCounterOffers), fills in as many of the most |
| 111 | // important counterOffers as will fit, and returns NEGOTIATE. As this implies a re-allocation, |
| 112 | // it should be used as a last resort. It is preferable for the offerer to simply allocate a |
| 113 | // larger space to begin with, and/or for the offeree to tolerate a smaller space than desired. |
| 114 | // Alternatively, the offerer can pass NULL for offers and counterOffers, and zero for |
| 115 | // numOffers. This indicates that it has not allocated space for any counter-offers yet. |
| 116 | // In this case, the offerree should set numCounterOffers appropriately and return NEGOTIATE. |
| 117 | // Then the offerer will allocate the correct amount of memory and retry. |
| 118 | // Format_Invalid is not allowed as either an offer or counter-offer. |
| 119 | // Returns: |
| 120 | // >= 0 Offer accepted. |
| 121 | // NEGOTIATE No offer accepted, and counter-offer(s) optionally made. See above for details. |
| 122 | virtual ssize_t negotiate(const NBAIO_Format offers[], size_t numOffers, |
| 123 | NBAIO_Format counterOffers[], size_t& numCounterOffers); |
| 124 | |
| 125 | // Return the current negotiated format, or Format_Invalid if negotiation has not been done, |
| 126 | // or if re-negotiation is required. |
| 127 | virtual NBAIO_Format format() const { return mNegotiated ? mFormat : Format_Invalid; } |
| 128 | |
| 129 | protected: |
Glenn Kasten | 72e54af | 2014-01-31 09:37:35 -0800 | [diff] [blame] | 130 | NBAIO_Port(const NBAIO_Format& format) : mNegotiated(false), mFormat(format), |
Glenn Kasten | ac3e9db | 2014-03-06 08:00:31 -0800 | [diff] [blame] | 131 | mBitShift(Format_frameBitShift(format)), |
| 132 | mFrameSize(Format_frameSize(format)) { } |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 133 | virtual ~NBAIO_Port() { } |
| 134 | |
| 135 | // Implementations are free to ignore these if they don't need them |
| 136 | |
| 137 | bool mNegotiated; // mNegotiated implies (mFormat != Format_Invalid) |
| 138 | NBAIO_Format mFormat; // (mFormat != Format_Invalid) does not imply mNegotiated |
| 139 | size_t mBitShift; // assign in parallel with any assignment to mFormat |
Glenn Kasten | ac3e9db | 2014-03-06 08:00:31 -0800 | [diff] [blame] | 140 | size_t mFrameSize; // assign in parallel with any assignment to mFormat |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 141 | }; |
| 142 | |
| 143 | // Abstract class (interface) representing a non-blocking data sink, for use by a data provider. |
| 144 | class NBAIO_Sink : public NBAIO_Port { |
| 145 | |
| 146 | public: |
| 147 | |
| 148 | // For the next two APIs: |
| 149 | // 32 bits rolls over after 27 hours at 44.1 kHz; if that concerns you then poll periodically. |
| 150 | |
| 151 | // Return the number of frames written successfully since construction. |
| 152 | virtual size_t framesWritten() const { return mFramesWritten; } |
| 153 | |
| 154 | // Number of frames lost due to underrun since construction. |
| 155 | virtual size_t framesUnderrun() const { return 0; } |
| 156 | |
| 157 | // Number of underruns since construction, where a set of contiguous lost frames is one event. |
| 158 | virtual size_t underruns() const { return 0; } |
| 159 | |
| 160 | // Estimate of number of frames that could be written successfully now without blocking. |
| 161 | // When a write() is actually attempted, the implementation is permitted to return a smaller or |
| 162 | // larger transfer count, however it will make a good faith effort to give an accurate estimate. |
| 163 | // Errors: |
| 164 | // NEGOTIATE (Re-)negotiation is needed. |
| 165 | // UNDERRUN write() has not been called frequently enough, or with enough frames to keep up. |
| 166 | // An underrun event is counted, and the caller should re-try this operation. |
| 167 | // WOULD_BLOCK Determining how many frames can be written without blocking would itself block. |
| 168 | virtual ssize_t availableToWrite() const { return SSIZE_MAX; } |
| 169 | |
| 170 | // Transfer data to sink from single input buffer. Implies a copy. |
| 171 | // Inputs: |
| 172 | // buffer Non-NULL buffer owned by provider. |
| 173 | // count Maximum number of frames to transfer. |
| 174 | // Return value: |
| 175 | // > 0 Number of frames successfully transferred prior to first error. |
| 176 | // = 0 Count was zero. |
| 177 | // < 0 status_t error occurred prior to the first frame transfer. |
| 178 | // Errors: |
| 179 | // NEGOTIATE (Re-)negotiation is needed. |
| 180 | // WOULD_BLOCK No frames can be transferred without blocking. |
| 181 | // UNDERRUN write() has not been called frequently enough, or with enough frames to keep up. |
| 182 | // An underrun event is counted, and the caller should re-try this operation. |
| 183 | virtual ssize_t write(const void *buffer, size_t count) = 0; |
| 184 | |
| 185 | // Transfer data to sink using a series of callbacks. More suitable for zero-fill, synthesis, |
| 186 | // and non-contiguous transfers (e.g. circular buffer or writev). |
| 187 | // Inputs: |
| 188 | // via Callback function that the sink will call as many times as needed to consume data. |
| 189 | // total Estimate of the number of frames the provider has available. This is an estimate, |
| 190 | // and it can provide a different number of frames during the series of callbacks. |
| 191 | // user Arbitrary void * reserved for data provider. |
| 192 | // block Number of frames per block, that is a suggested value for 'count' in each callback. |
| 193 | // Zero means no preference. This parameter is a hint only, and may be ignored. |
| 194 | // Return value: |
| 195 | // > 0 Total number of frames successfully transferred prior to first error. |
| 196 | // = 0 Count was zero. |
| 197 | // < 0 status_t error occurred prior to the first frame transfer. |
| 198 | // Errors: |
| 199 | // NEGOTIATE (Re-)negotiation is needed. |
| 200 | // WOULD_BLOCK No frames can be transferred without blocking. |
| 201 | // UNDERRUN write() has not been called frequently enough, or with enough frames to keep up. |
| 202 | // An underrun event is counted, and the caller should re-try this operation. |
| 203 | // |
| 204 | // The 'via' callback is called by the data sink as follows: |
| 205 | // Inputs: |
| 206 | // user Arbitrary void * reserved for data provider. |
| 207 | // buffer Non-NULL buffer owned by sink that callback should fill in with data, |
| 208 | // up to a maximum of 'count' frames. |
| 209 | // count Maximum number of frames to transfer during this callback. |
| 210 | // Return value: |
| 211 | // > 0 Number of frames successfully transferred during this callback prior to first error. |
| 212 | // = 0 Count was zero. |
| 213 | // < 0 status_t error occurred prior to the first frame transfer during this callback. |
| 214 | virtual ssize_t writeVia(writeVia_t via, size_t total, void *user, size_t block = 0); |
| 215 | |
John Grossman | 2c3b2da | 2012-08-02 17:08:54 -0700 | [diff] [blame] | 216 | // Get the time (on the LocalTime timeline) at which the first frame of audio of the next write |
| 217 | // operation to this sink will be eventually rendered by the HAL. |
| 218 | // Inputs: |
| 219 | // ts A pointer pointing to the int64_t which will hold the result. |
| 220 | // Return value: |
| 221 | // OK Everything went well, *ts holds the time at which the first audio frame of the next |
| 222 | // write operation will be rendered, or AudioBufferProvider::kInvalidPTS if this sink |
| 223 | // does not know the answer for some reason. Sinks which eventually lead to a HAL |
| 224 | // which implements get_next_write_timestamp may return Invalid temporarily if the DMA |
| 225 | // output of the audio driver has not started yet. Sinks which lead to a HAL which |
| 226 | // does not implement get_next_write_timestamp, or which don't lead to a HAL at all, |
| 227 | // will always return kInvalidPTS. |
| 228 | // <other> Something unexpected happened internally. Check the logs and start debugging. |
| 229 | virtual status_t getNextWriteTimestamp(int64_t *ts) { return INVALID_OPERATION; } |
| 230 | |
Glenn Kasten | 767094d | 2013-08-23 13:51:43 -0700 | [diff] [blame] | 231 | // Returns NO_ERROR if a timestamp is available. The timestamp includes the total number |
| 232 | // of frames presented to an external observer, together with the value of CLOCK_MONOTONIC |
| 233 | // as of this presentation count. |
| 234 | virtual status_t getTimestamp(AudioTimestamp& timestamp) { return INVALID_OPERATION; } |
| 235 | |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 236 | protected: |
Glenn Kasten | 72e54af | 2014-01-31 09:37:35 -0800 | [diff] [blame] | 237 | NBAIO_Sink(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesWritten(0) { } |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 238 | virtual ~NBAIO_Sink() { } |
| 239 | |
| 240 | // Implementations are free to ignore these if they don't need them |
| 241 | size_t mFramesWritten; |
| 242 | }; |
| 243 | |
| 244 | // Abstract class (interface) representing a non-blocking data source, for use by a data consumer. |
| 245 | class NBAIO_Source : public NBAIO_Port { |
| 246 | |
| 247 | public: |
| 248 | |
| 249 | // For the next two APIs: |
| 250 | // 32 bits rolls over after 27 hours at 44.1 kHz; if that concerns you then poll periodically. |
| 251 | |
| 252 | // Number of frames read successfully since construction. |
| 253 | virtual size_t framesRead() const { return mFramesRead; } |
| 254 | |
| 255 | // Number of frames lost due to overrun since construction. |
| 256 | // Not const because implementations may need to do I/O. |
| 257 | virtual size_t framesOverrun() /*const*/ { return 0; } |
| 258 | |
| 259 | // Number of overruns since construction, where a set of contiguous lost frames is one event. |
| 260 | // Not const because implementations may need to do I/O. |
| 261 | virtual size_t overruns() /*const*/ { return 0; } |
| 262 | |
| 263 | // Estimate of number of frames that could be read successfully now. |
| 264 | // When a read() is actually attempted, the implementation is permitted to return a smaller or |
| 265 | // larger transfer count, however it will make a good faith effort to give an accurate estimate. |
| 266 | // Errors: |
| 267 | // NEGOTIATE (Re-)negotiation is needed. |
| 268 | // OVERRUN One or more frames were lost due to overrun, try again to read more recent data. |
| 269 | // WOULD_BLOCK Determining how many frames can be read without blocking would itself block. |
| 270 | virtual ssize_t availableToRead() { return SSIZE_MAX; } |
| 271 | |
| 272 | // Transfer data from source into single destination buffer. Implies a copy. |
| 273 | // Inputs: |
| 274 | // buffer Non-NULL destination buffer owned by consumer. |
| 275 | // count Maximum number of frames to transfer. |
John Grossman | 2c3b2da | 2012-08-02 17:08:54 -0700 | [diff] [blame] | 276 | // readPTS The presentation time (on the LocalTime timeline) for which data |
| 277 | // is being requested, or kInvalidPTS if not known. |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 278 | // Return value: |
| 279 | // > 0 Number of frames successfully transferred prior to first error. |
| 280 | // = 0 Count was zero. |
| 281 | // < 0 status_t error occurred prior to the first frame transfer. |
| 282 | // Errors: |
| 283 | // NEGOTIATE (Re-)negotiation is needed. |
| 284 | // WOULD_BLOCK No frames can be transferred without blocking. |
| 285 | // OVERRUN read() has not been called frequently enough, or with enough frames to keep up. |
| 286 | // One or more frames were lost due to overrun, try again to read more recent data. |
John Grossman | 2c3b2da | 2012-08-02 17:08:54 -0700 | [diff] [blame] | 287 | virtual ssize_t read(void *buffer, size_t count, int64_t readPTS) = 0; |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 288 | |
| 289 | // Transfer data from source using a series of callbacks. More suitable for zero-fill, |
| 290 | // synthesis, and non-contiguous transfers (e.g. circular buffer or readv). |
| 291 | // Inputs: |
| 292 | // via Callback function that the source will call as many times as needed to provide data. |
| 293 | // total Estimate of the number of frames the consumer desires. This is an estimate, |
| 294 | // and it can consume a different number of frames during the series of callbacks. |
| 295 | // user Arbitrary void * reserved for data consumer. |
John Grossman | 2c3b2da | 2012-08-02 17:08:54 -0700 | [diff] [blame] | 296 | // readPTS The presentation time (on the LocalTime timeline) for which data |
| 297 | // is being requested, or kInvalidPTS if not known. |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 298 | // block Number of frames per block, that is a suggested value for 'count' in each callback. |
| 299 | // Zero means no preference. This parameter is a hint only, and may be ignored. |
| 300 | // Return value: |
| 301 | // > 0 Total number of frames successfully transferred prior to first error. |
| 302 | // = 0 Count was zero. |
| 303 | // < 0 status_t error occurred prior to the first frame transfer. |
| 304 | // Errors: |
| 305 | // NEGOTIATE (Re-)negotiation is needed. |
| 306 | // WOULD_BLOCK No frames can be transferred without blocking. |
| 307 | // OVERRUN read() has not been called frequently enough, or with enough frames to keep up. |
| 308 | // One or more frames were lost due to overrun, try again to read more recent data. |
| 309 | // |
| 310 | // The 'via' callback is called by the data source as follows: |
| 311 | // Inputs: |
| 312 | // user Arbitrary void * reserved for data consumer. |
| 313 | // dest Non-NULL buffer owned by source that callback should consume data from, |
| 314 | // up to a maximum of 'count' frames. |
| 315 | // count Maximum number of frames to transfer during this callback. |
| 316 | // Return value: |
| 317 | // > 0 Number of frames successfully transferred during this callback prior to first error. |
| 318 | // = 0 Count was zero. |
| 319 | // < 0 status_t error occurred prior to the first frame transfer during this callback. |
John Grossman | 2c3b2da | 2012-08-02 17:08:54 -0700 | [diff] [blame] | 320 | virtual ssize_t readVia(readVia_t via, size_t total, void *user, |
| 321 | int64_t readPTS, size_t block = 0); |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 322 | |
Glenn Kasten | 894d6be | 2013-08-26 10:29:28 -0700 | [diff] [blame] | 323 | // Invoked asynchronously by corresponding sink when a new timestamp is available. |
| 324 | // Default implementation ignores the timestamp. |
| 325 | virtual void onTimestamp(const AudioTimestamp& timestamp) { } |
| 326 | |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 327 | protected: |
Glenn Kasten | 72e54af | 2014-01-31 09:37:35 -0800 | [diff] [blame] | 328 | NBAIO_Source(const NBAIO_Format& format = Format_Invalid) : NBAIO_Port(format), mFramesRead(0) { } |
Glenn Kasten | 0106623 | 2012-02-27 11:50:44 -0800 | [diff] [blame] | 329 | virtual ~NBAIO_Source() { } |
| 330 | |
| 331 | // Implementations are free to ignore these if they don't need them |
| 332 | size_t mFramesRead; |
| 333 | }; |
| 334 | |
| 335 | } // namespace android |
| 336 | |
| 337 | #endif // ANDROID_AUDIO_NBAIO_H |