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(const NBAIO_Format & format)25 size_t Format_frameSize(const NBAIO_Format& format)
26 {
27 return format.mFrameSize;
28 }
29
30 const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 };
31
Format_sampleRate(const NBAIO_Format & format)32 unsigned Format_sampleRate(const NBAIO_Format& format)
33 {
34 if (!Format_isValid(format)) {
35 return 0;
36 }
37 return format.mSampleRate;
38 }
39
Format_channelCount(const NBAIO_Format & format)40 unsigned Format_channelCount(const NBAIO_Format& format)
41 {
42 if (!Format_isValid(format)) {
43 return 0;
44 }
45 return format.mChannelCount;
46 }
47
Format_from_SR_C(unsigned sampleRate,unsigned channelCount,audio_format_t format)48 NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount,
49 audio_format_t format)
50 {
51 if (sampleRate == 0 || channelCount == 0 || !audio_is_valid_format(format)) {
52 return Format_Invalid;
53 }
54 NBAIO_Format ret;
55 ret.mSampleRate = sampleRate;
56 ret.mChannelCount = channelCount;
57 ret.mFormat = format;
58 ret.mFrameSize = audio_is_linear_pcm(format) ?
59 channelCount * audio_bytes_per_sample(format) : sizeof(uint8_t);
60 return ret;
61 }
62
63 // 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)64 ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
65 {
66 if (!mNegotiated) {
67 return (ssize_t) NEGOTIATE;
68 }
69 static const size_t maxBlock = 32;
70 size_t frameSize = Format_frameSize(mFormat);
71 ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
72 // double guarantees alignment for stack similar to what malloc() gives for heap
73 if (block == 0 || block > maxBlock) {
74 block = maxBlock;
75 }
76 double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
77 size_t accumulator = 0;
78 while (accumulator < total) {
79 size_t count = total - accumulator;
80 if (count > block) {
81 count = block;
82 }
83 ssize_t ret = via(user, buffer, count);
84 if (ret > 0) {
85 ALOG_ASSERT((size_t) ret <= count);
86 size_t maxRet = ret;
87 ret = write(buffer, maxRet);
88 if (ret > 0) {
89 ALOG_ASSERT((size_t) ret <= maxRet);
90 accumulator += ret;
91 continue;
92 }
93 }
94 return accumulator > 0 ? accumulator : ret;
95 }
96 return accumulator;
97 }
98
99 // 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)100 ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user,
101 int64_t readPTS, size_t block)
102 {
103 if (!mNegotiated) {
104 return (ssize_t) NEGOTIATE;
105 }
106 static const size_t maxBlock = 32;
107 size_t frameSize = Format_frameSize(mFormat);
108 ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
109 // double guarantees alignment for stack similar to what malloc() gives for heap
110 if (block == 0 || block > maxBlock) {
111 block = maxBlock;
112 }
113 double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
114 size_t accumulator = 0;
115 while (accumulator < total) {
116 size_t count = total - accumulator;
117 if (count > block) {
118 count = block;
119 }
120 ssize_t ret = read(buffer, count, readPTS);
121 if (ret > 0) {
122 ALOG_ASSERT((size_t) ret <= count);
123 size_t maxRet = ret;
124 ret = via(user, buffer, maxRet, readPTS);
125 if (ret > 0) {
126 ALOG_ASSERT((size_t) ret <= maxRet);
127 accumulator += ret;
128 continue;
129 }
130 }
131 return accumulator > 0 ? accumulator : ret;
132 }
133 return accumulator;
134 }
135
136 // Default implementation that only accepts my mFormat
negotiate(const NBAIO_Format offers[],size_t numOffers,NBAIO_Format counterOffers[],size_t & numCounterOffers)137 ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
138 NBAIO_Format counterOffers[], size_t& numCounterOffers)
139 {
140 ALOGV("negotiate offers=%p numOffers=%zu countersOffers=%p numCounterOffers=%zu",
141 offers, numOffers, counterOffers, numCounterOffers);
142 if (Format_isValid(mFormat)) {
143 for (size_t i = 0; i < numOffers; ++i) {
144 if (Format_isEqual(offers[i], mFormat)) {
145 mNegotiated = true;
146 return i;
147 }
148 }
149 if (numCounterOffers > 0) {
150 counterOffers[0] = mFormat;
151 }
152 numCounterOffers = 1;
153 } else {
154 numCounterOffers = 0;
155 }
156 return (ssize_t) NEGOTIATE;
157 }
158
Format_isValid(const NBAIO_Format & format)159 bool Format_isValid(const NBAIO_Format& format)
160 {
161 return format.mSampleRate != 0 && format.mChannelCount != 0 &&
162 format.mFormat != AUDIO_FORMAT_INVALID && format.mFrameSize != 0;
163 }
164
Format_isEqual(const NBAIO_Format & format1,const NBAIO_Format & format2)165 bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2)
166 {
167 return format1.mSampleRate == format2.mSampleRate &&
168 format1.mChannelCount == format2.mChannelCount && format1.mFormat == format2.mFormat &&
169 format1.mFrameSize == format2.mFrameSize;
170 }
171
172 } // namespace android
173