• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define LOG_TAG "NBAIO"
18 //#define LOG_NDEBUG 0
19 
20 #include <utils/Log.h>
21 #include <media/nbaio/NBAIO.h>
22 
23 namespace android {
24 
Format_frameSize(NBAIO_Format format)25 size_t Format_frameSize(NBAIO_Format format)
26 {
27     return Format_channelCount(format) * sizeof(short);
28 }
29 
Format_frameBitShift(NBAIO_Format format)30 size_t Format_frameBitShift(NBAIO_Format format)
31 {
32     // sizeof(short) == 2, so frame size == 1 << channels
33     return Format_channelCount(format);
34 }
35 
36 enum {
37     Format_SR_8000,
38     Format_SR_11025,
39     Format_SR_16000,
40     Format_SR_22050,
41     Format_SR_24000,
42     Format_SR_32000,
43     Format_SR_44100,
44     Format_SR_48000,
45     Format_SR_Mask = 7
46 };
47 
48 enum {
49     Format_C_1 = 0x08,
50     Format_C_2 = 0x10,
51     Format_C_Mask = 0x18
52 };
53 
Format_sampleRate(NBAIO_Format format)54 unsigned Format_sampleRate(NBAIO_Format format)
55 {
56     if (format == Format_Invalid) {
57         return 0;
58     }
59     switch (format & Format_SR_Mask) {
60     case Format_SR_8000:
61         return 8000;
62     case Format_SR_11025:
63         return 11025;
64     case Format_SR_16000:
65         return 16000;
66     case Format_SR_22050:
67         return 22050;
68     case Format_SR_24000:
69         return 24000;
70     case Format_SR_32000:
71         return 32000;
72     case Format_SR_44100:
73         return 44100;
74     case Format_SR_48000:
75         return 48000;
76     default:
77         return 0;
78     }
79 }
80 
Format_channelCount(NBAIO_Format format)81 unsigned Format_channelCount(NBAIO_Format format)
82 {
83     if (format == Format_Invalid) {
84         return 0;
85     }
86     switch (format & Format_C_Mask) {
87     case Format_C_1:
88         return 1;
89     case Format_C_2:
90         return 2;
91     default:
92         return 0;
93     }
94 }
95 
Format_from_SR_C(unsigned sampleRate,unsigned channelCount)96 NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount)
97 {
98     NBAIO_Format format;
99     switch (sampleRate) {
100     case 8000:
101         format = Format_SR_8000;
102         break;
103     case 11025:
104         format = Format_SR_11025;
105         break;
106     case 16000:
107         format = Format_SR_16000;
108         break;
109     case 22050:
110         format = Format_SR_22050;
111         break;
112     case 24000:
113         format = Format_SR_24000;
114         break;
115     case 32000:
116         format = Format_SR_32000;
117         break;
118     case 44100:
119         format = Format_SR_44100;
120         break;
121     case 48000:
122         format = Format_SR_48000;
123         break;
124     default:
125         return Format_Invalid;
126     }
127     switch (channelCount) {
128     case 1:
129         format |= Format_C_1;
130         break;
131     case 2:
132         format |= Format_C_2;
133         break;
134     default:
135         return Format_Invalid;
136     }
137     return format;
138 }
139 
140 // This is a default implementation; it is expected that subclasses will optimize this.
writeVia(writeVia_t via,size_t total,void * user,size_t block)141 ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
142 {
143     if (!mNegotiated) {
144         return (ssize_t) NEGOTIATE;
145     }
146     static const size_t maxBlock = 32;
147     size_t frameSize = Format_frameSize(mFormat);
148     ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
149     // double guarantees alignment for stack similar to what malloc() gives for heap
150     if (block == 0 || block > maxBlock) {
151         block = maxBlock;
152     }
153     double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
154     size_t accumulator = 0;
155     while (accumulator < total) {
156         size_t count = total - accumulator;
157         if (count > block) {
158             count = block;
159         }
160         ssize_t ret = via(user, buffer, count);
161         if (ret > 0) {
162             ALOG_ASSERT((size_t) ret <= count);
163             size_t maxRet = ret;
164             ret = write(buffer, maxRet);
165             if (ret > 0) {
166                 ALOG_ASSERT((size_t) ret <= maxRet);
167                 accumulator += ret;
168                 continue;
169             }
170         }
171         return accumulator > 0 ? accumulator : ret;
172     }
173     return accumulator;
174 }
175 
176 // This is a default implementation; it is expected that subclasses will optimize this.
readVia(readVia_t via,size_t total,void * user,int64_t readPTS,size_t block)177 ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
178                               int64_t readPTS, size_t block)
179 {
180     if (!mNegotiated) {
181         return (ssize_t) NEGOTIATE;
182     }
183     static const size_t maxBlock = 32;
184     size_t frameSize = Format_frameSize(mFormat);
185     ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
186     // double guarantees alignment for stack similar to what malloc() gives for heap
187     if (block == 0 || block > maxBlock) {
188         block = maxBlock;
189     }
190     double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
191     size_t accumulator = 0;
192     while (accumulator < total) {
193         size_t count = total - accumulator;
194         if (count > block) {
195             count = block;
196         }
197         ssize_t ret = read(buffer, count, readPTS);
198         if (ret > 0) {
199             ALOG_ASSERT((size_t) ret <= count);
200             size_t maxRet = ret;
201             ret = via(user, buffer, maxRet, readPTS);
202             if (ret > 0) {
203                 ALOG_ASSERT((size_t) ret <= maxRet);
204                 accumulator += ret;
205                 continue;
206             }
207         }
208         return accumulator > 0 ? accumulator : ret;
209     }
210     return accumulator;
211 }
212 
213 // Default implementation that only accepts my mFormat
negotiate(const NBAIO_Format offers[],size_t numOffers,NBAIO_Format counterOffers[],size_t & numCounterOffers)214 ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
215                                   NBAIO_Format counterOffers[], size_t& numCounterOffers)
216 {
217     ALOGV("negotiate offers=%p numOffers=%u countersOffers=%p numCounterOffers=%u",
218             offers, numOffers, counterOffers, numCounterOffers);
219     if (mFormat != Format_Invalid) {
220         for (size_t i = 0; i < numOffers; ++i) {
221             if (offers[i] == mFormat) {
222                 mNegotiated = true;
223                 return i;
224             }
225         }
226         if (numCounterOffers > 0) {
227             counterOffers[0] = mFormat;
228         }
229         numCounterOffers = 1;
230     } else {
231         numCounterOffers = 0;
232     }
233     return (ssize_t) NEGOTIATE;
234 }
235 
236 }   // namespace android
237