xref: /aosp_15_r20/frameworks/av/media/libnbaio/NBAIO.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2012 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "NBAIO"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <media/nbaio/NBAIO.h>
22*ec779b8eSAndroid Build Coastguard Worker 
23*ec779b8eSAndroid Build Coastguard Worker namespace android {
24*ec779b8eSAndroid Build Coastguard Worker 
Format_frameSize(const NBAIO_Format & format)25*ec779b8eSAndroid Build Coastguard Worker size_t Format_frameSize(const NBAIO_Format& format)
26*ec779b8eSAndroid Build Coastguard Worker {
27*ec779b8eSAndroid Build Coastguard Worker     return format.mFrameSize;
28*ec779b8eSAndroid Build Coastguard Worker }
29*ec779b8eSAndroid Build Coastguard Worker 
30*ec779b8eSAndroid Build Coastguard Worker const NBAIO_Format Format_Invalid = { 0, 0, AUDIO_FORMAT_INVALID, 0 };
31*ec779b8eSAndroid Build Coastguard Worker 
Format_sampleRate(const NBAIO_Format & format)32*ec779b8eSAndroid Build Coastguard Worker unsigned Format_sampleRate(const NBAIO_Format& format)
33*ec779b8eSAndroid Build Coastguard Worker {
34*ec779b8eSAndroid Build Coastguard Worker     if (!Format_isValid(format)) {
35*ec779b8eSAndroid Build Coastguard Worker         return 0;
36*ec779b8eSAndroid Build Coastguard Worker     }
37*ec779b8eSAndroid Build Coastguard Worker     return format.mSampleRate;
38*ec779b8eSAndroid Build Coastguard Worker }
39*ec779b8eSAndroid Build Coastguard Worker 
Format_channelCount(const NBAIO_Format & format)40*ec779b8eSAndroid Build Coastguard Worker unsigned Format_channelCount(const NBAIO_Format& format)
41*ec779b8eSAndroid Build Coastguard Worker {
42*ec779b8eSAndroid Build Coastguard Worker     if (!Format_isValid(format)) {
43*ec779b8eSAndroid Build Coastguard Worker         return 0;
44*ec779b8eSAndroid Build Coastguard Worker     }
45*ec779b8eSAndroid Build Coastguard Worker     return format.mChannelCount;
46*ec779b8eSAndroid Build Coastguard Worker }
47*ec779b8eSAndroid Build Coastguard Worker 
Format_from_SR_C(unsigned sampleRate,unsigned channelCount,audio_format_t format)48*ec779b8eSAndroid Build Coastguard Worker NBAIO_Format Format_from_SR_C(unsigned sampleRate, unsigned channelCount,
49*ec779b8eSAndroid Build Coastguard Worker         audio_format_t format)
50*ec779b8eSAndroid Build Coastguard Worker {
51*ec779b8eSAndroid Build Coastguard Worker     if (sampleRate == 0 || channelCount == 0 || !audio_is_valid_format(format)) {
52*ec779b8eSAndroid Build Coastguard Worker         return Format_Invalid;
53*ec779b8eSAndroid Build Coastguard Worker     }
54*ec779b8eSAndroid Build Coastguard Worker     NBAIO_Format ret;
55*ec779b8eSAndroid Build Coastguard Worker     ret.mSampleRate = sampleRate;
56*ec779b8eSAndroid Build Coastguard Worker     ret.mChannelCount = channelCount;
57*ec779b8eSAndroid Build Coastguard Worker     ret.mFormat = format;
58*ec779b8eSAndroid Build Coastguard Worker     ret.mFrameSize = audio_bytes_per_frame(channelCount, format);
59*ec779b8eSAndroid Build Coastguard Worker     return ret;
60*ec779b8eSAndroid Build Coastguard Worker }
61*ec779b8eSAndroid Build Coastguard Worker 
62*ec779b8eSAndroid Build Coastguard Worker // 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)63*ec779b8eSAndroid Build Coastguard Worker ssize_t NBAIO_Sink::writeVia(writeVia_t via, size_t total, void *user, size_t block)
64*ec779b8eSAndroid Build Coastguard Worker {
65*ec779b8eSAndroid Build Coastguard Worker     if (!mNegotiated) {
66*ec779b8eSAndroid Build Coastguard Worker         return (ssize_t) NEGOTIATE;
67*ec779b8eSAndroid Build Coastguard Worker     }
68*ec779b8eSAndroid Build Coastguard Worker     static const size_t maxBlock = 32;
69*ec779b8eSAndroid Build Coastguard Worker     size_t frameSize = Format_frameSize(mFormat);
70*ec779b8eSAndroid Build Coastguard Worker     ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
71*ec779b8eSAndroid Build Coastguard Worker     // double guarantees alignment for stack similar to what malloc() gives for heap
72*ec779b8eSAndroid Build Coastguard Worker     if (block == 0 || block > maxBlock) {
73*ec779b8eSAndroid Build Coastguard Worker         block = maxBlock;
74*ec779b8eSAndroid Build Coastguard Worker     }
75*ec779b8eSAndroid Build Coastguard Worker     double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
76*ec779b8eSAndroid Build Coastguard Worker     size_t accumulator = 0;
77*ec779b8eSAndroid Build Coastguard Worker     while (accumulator < total) {
78*ec779b8eSAndroid Build Coastguard Worker         size_t count = total - accumulator;
79*ec779b8eSAndroid Build Coastguard Worker         if (count > block) {
80*ec779b8eSAndroid Build Coastguard Worker             count = block;
81*ec779b8eSAndroid Build Coastguard Worker         }
82*ec779b8eSAndroid Build Coastguard Worker         ssize_t ret = via(user, buffer, count);
83*ec779b8eSAndroid Build Coastguard Worker         if (ret > 0) {
84*ec779b8eSAndroid Build Coastguard Worker             ALOG_ASSERT((size_t) ret <= count);
85*ec779b8eSAndroid Build Coastguard Worker             size_t maxRet = ret;
86*ec779b8eSAndroid Build Coastguard Worker             ret = write(buffer, maxRet);
87*ec779b8eSAndroid Build Coastguard Worker             if (ret > 0) {
88*ec779b8eSAndroid Build Coastguard Worker                 ALOG_ASSERT((size_t) ret <= maxRet);
89*ec779b8eSAndroid Build Coastguard Worker                 accumulator += ret;
90*ec779b8eSAndroid Build Coastguard Worker                 continue;
91*ec779b8eSAndroid Build Coastguard Worker             }
92*ec779b8eSAndroid Build Coastguard Worker         }
93*ec779b8eSAndroid Build Coastguard Worker         return accumulator > 0 ? accumulator : ret;
94*ec779b8eSAndroid Build Coastguard Worker     }
95*ec779b8eSAndroid Build Coastguard Worker     return accumulator;
96*ec779b8eSAndroid Build Coastguard Worker }
97*ec779b8eSAndroid Build Coastguard Worker 
98*ec779b8eSAndroid Build Coastguard Worker // This is a default implementation; it is expected that subclasses will optimize this.
readVia(readVia_t via,size_t total,void * user,size_t block)99*ec779b8eSAndroid Build Coastguard Worker ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, size_t block)
100*ec779b8eSAndroid Build Coastguard Worker {
101*ec779b8eSAndroid Build Coastguard Worker     if (!mNegotiated) {
102*ec779b8eSAndroid Build Coastguard Worker         return (ssize_t) NEGOTIATE;
103*ec779b8eSAndroid Build Coastguard Worker     }
104*ec779b8eSAndroid Build Coastguard Worker     static const size_t maxBlock = 32;
105*ec779b8eSAndroid Build Coastguard Worker     size_t frameSize = Format_frameSize(mFormat);
106*ec779b8eSAndroid Build Coastguard Worker     ALOG_ASSERT(frameSize > 0 && frameSize <= 8);
107*ec779b8eSAndroid Build Coastguard Worker     // double guarantees alignment for stack similar to what malloc() gives for heap
108*ec779b8eSAndroid Build Coastguard Worker     if (block == 0 || block > maxBlock) {
109*ec779b8eSAndroid Build Coastguard Worker         block = maxBlock;
110*ec779b8eSAndroid Build Coastguard Worker     }
111*ec779b8eSAndroid Build Coastguard Worker     double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)];
112*ec779b8eSAndroid Build Coastguard Worker     size_t accumulator = 0;
113*ec779b8eSAndroid Build Coastguard Worker     while (accumulator < total) {
114*ec779b8eSAndroid Build Coastguard Worker         size_t count = total - accumulator;
115*ec779b8eSAndroid Build Coastguard Worker         if (count > block) {
116*ec779b8eSAndroid Build Coastguard Worker             count = block;
117*ec779b8eSAndroid Build Coastguard Worker         }
118*ec779b8eSAndroid Build Coastguard Worker         ssize_t ret = read(buffer, count);
119*ec779b8eSAndroid Build Coastguard Worker         if (ret > 0) {
120*ec779b8eSAndroid Build Coastguard Worker             ALOG_ASSERT((size_t) ret <= count);
121*ec779b8eSAndroid Build Coastguard Worker             size_t maxRet = ret;
122*ec779b8eSAndroid Build Coastguard Worker             ret = via(user, buffer, maxRet);
123*ec779b8eSAndroid Build Coastguard Worker             if (ret > 0) {
124*ec779b8eSAndroid Build Coastguard Worker                 ALOG_ASSERT((size_t) ret <= maxRet);
125*ec779b8eSAndroid Build Coastguard Worker                 accumulator += ret;
126*ec779b8eSAndroid Build Coastguard Worker                 continue;
127*ec779b8eSAndroid Build Coastguard Worker             }
128*ec779b8eSAndroid Build Coastguard Worker         }
129*ec779b8eSAndroid Build Coastguard Worker         return accumulator > 0 ? accumulator : ret;
130*ec779b8eSAndroid Build Coastguard Worker     }
131*ec779b8eSAndroid Build Coastguard Worker     return accumulator;
132*ec779b8eSAndroid Build Coastguard Worker }
133*ec779b8eSAndroid Build Coastguard Worker 
134*ec779b8eSAndroid Build Coastguard Worker // Default implementation that only accepts my mFormat
negotiate(const NBAIO_Format offers[],size_t numOffers,NBAIO_Format counterOffers[],size_t & numCounterOffers)135*ec779b8eSAndroid Build Coastguard Worker ssize_t NBAIO_Port::negotiate(const NBAIO_Format offers[], size_t numOffers,
136*ec779b8eSAndroid Build Coastguard Worker                                   NBAIO_Format counterOffers[], size_t& numCounterOffers)
137*ec779b8eSAndroid Build Coastguard Worker {
138*ec779b8eSAndroid Build Coastguard Worker     ALOGV("negotiate offers=%p numOffers=%zu countersOffers=%p numCounterOffers=%zu",
139*ec779b8eSAndroid Build Coastguard Worker             offers, numOffers, counterOffers, numCounterOffers);
140*ec779b8eSAndroid Build Coastguard Worker     if (Format_isValid(mFormat)) {
141*ec779b8eSAndroid Build Coastguard Worker         for (size_t i = 0; i < numOffers; ++i) {
142*ec779b8eSAndroid Build Coastguard Worker             if (Format_isEqual(offers[i], mFormat)) {
143*ec779b8eSAndroid Build Coastguard Worker                 mNegotiated = true;
144*ec779b8eSAndroid Build Coastguard Worker                 return i;
145*ec779b8eSAndroid Build Coastguard Worker             }
146*ec779b8eSAndroid Build Coastguard Worker         }
147*ec779b8eSAndroid Build Coastguard Worker         if (numCounterOffers > 0) {
148*ec779b8eSAndroid Build Coastguard Worker             counterOffers[0] = mFormat;
149*ec779b8eSAndroid Build Coastguard Worker         }
150*ec779b8eSAndroid Build Coastguard Worker         numCounterOffers = 1;
151*ec779b8eSAndroid Build Coastguard Worker     } else {
152*ec779b8eSAndroid Build Coastguard Worker         numCounterOffers = 0;
153*ec779b8eSAndroid Build Coastguard Worker     }
154*ec779b8eSAndroid Build Coastguard Worker     return (ssize_t) NEGOTIATE;
155*ec779b8eSAndroid Build Coastguard Worker }
156*ec779b8eSAndroid Build Coastguard Worker 
Format_isValid(const NBAIO_Format & format)157*ec779b8eSAndroid Build Coastguard Worker bool Format_isValid(const NBAIO_Format& format)
158*ec779b8eSAndroid Build Coastguard Worker {
159*ec779b8eSAndroid Build Coastguard Worker     return format.mSampleRate != 0 && format.mChannelCount != 0 &&
160*ec779b8eSAndroid Build Coastguard Worker             format.mFormat != AUDIO_FORMAT_INVALID && format.mFrameSize != 0;
161*ec779b8eSAndroid Build Coastguard Worker }
162*ec779b8eSAndroid Build Coastguard Worker 
Format_isEqual(const NBAIO_Format & format1,const NBAIO_Format & format2)163*ec779b8eSAndroid Build Coastguard Worker bool Format_isEqual(const NBAIO_Format& format1, const NBAIO_Format& format2)
164*ec779b8eSAndroid Build Coastguard Worker {
165*ec779b8eSAndroid Build Coastguard Worker     return format1.mSampleRate == format2.mSampleRate &&
166*ec779b8eSAndroid Build Coastguard Worker             format1.mChannelCount == format2.mChannelCount && format1.mFormat == format2.mFormat &&
167*ec779b8eSAndroid Build Coastguard Worker             format1.mFrameSize == format2.mFrameSize;
168*ec779b8eSAndroid Build Coastguard Worker }
169*ec779b8eSAndroid Build Coastguard Worker 
170*ec779b8eSAndroid Build Coastguard Worker }   // namespace android
171