blob: fd16e9204d601876da8c3537af12cce091d1c821 [file] [log] [blame]
Glenn Kasten01066232012-02-27 11:50:44 -08001/*
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 "MonoPipe"
18//#define LOG_NDEBUG 0
19
20#include <cutils/atomic.h>
21#include <cutils/compiler.h>
22#include <utils/Log.h>
23#include "MonoPipe.h"
24#include "roundup.h"
25
26namespace android {
27
28MonoPipe::MonoPipe(size_t maxFrames, NBAIO_Format format, bool writeCanBlock) :
29 NBAIO_Sink(format),
30 mMaxFrames(roundup(maxFrames)),
31 mBuffer(malloc(mMaxFrames * Format_frameSize(format))),
32 mFront(0),
33 mRear(0),
34 mWriteCanBlock(writeCanBlock)
35{
Glenn Kasten01066232012-02-27 11:50:44 -080036}
37
38MonoPipe::~MonoPipe()
39{
40 free(mBuffer);
41}
42
43ssize_t MonoPipe::availableToWrite() const
44{
45 if (CC_UNLIKELY(!mNegotiated)) {
46 return NEGOTIATE;
47 }
48 ssize_t ret = mMaxFrames - (mRear - android_atomic_acquire_load(&mFront));
49 ALOG_ASSERT((0 <= ret) && (ret <= mMaxFrames));
50 return ret;
51}
52
53ssize_t MonoPipe::write(const void *buffer, size_t count)
54{
Glenn Kasten01066232012-02-27 11:50:44 -080055 if (CC_UNLIKELY(!mNegotiated)) {
56 return NEGOTIATE;
57 }
58 size_t totalFramesWritten = 0;
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070059 while (count > 0) {
60 size_t avail = availableToWrite();
61 size_t written = avail;
Glenn Kasten01066232012-02-27 11:50:44 -080062 if (CC_LIKELY(written > count)) {
63 written = count;
64 }
65 size_t rear = mRear & (mMaxFrames - 1);
66 size_t part1 = mMaxFrames - rear;
67 if (part1 > written) {
68 part1 = written;
69 }
70 if (CC_LIKELY(part1 > 0)) {
71 memcpy((char *) mBuffer + (rear << mBitShift), buffer, part1 << mBitShift);
72 if (CC_UNLIKELY(rear + part1 == mMaxFrames)) {
73 size_t part2 = written - part1;
74 if (CC_LIKELY(part2 > 0)) {
75 memcpy(mBuffer, (char *) buffer + (part1 << mBitShift), part2 << mBitShift);
76 }
77 }
78 android_atomic_release_store(written + mRear, &mRear);
79 totalFramesWritten += written;
80 }
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070081 if (!mWriteCanBlock) {
Glenn Kasten01066232012-02-27 11:50:44 -080082 break;
83 }
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070084 count -= written;
Glenn Kasten01066232012-02-27 11:50:44 -080085 buffer = (char *) buffer + (written << mBitShift);
Glenn Kasten6d8aabe2012-05-18 10:47:28 -070086 // Simulate blocking I/O by sleeping at different rates, depending on a throttle.
87 // The throttle tries to keep the pipe about 5/8 full on average, with a slight jitter.
88 uint64_t ns;
89 enum {
90 THROTTLE_VERY_FAST, // pipe is (nearly) empty, fill quickly
91 THROTTLE_FAST, // pipe is normal, fill at slightly faster rate
92 THROTTLE_NOMINAL, // pipe is normal, fill at nominal rate
93 THROTTLE_SLOW, // pipe is normal, fill at slightly slower rate
94 THROTTLE_VERY_SLOW, // pipe is (nearly) full, fill slowly
95 } throttle;
96 avail -= written;
97 // FIXME cache these values to avoid re-computation
98 if (avail >= (mMaxFrames * 3) / 4) {
99 throttle = THROTTLE_VERY_FAST;
100 } else if (avail >= mMaxFrames / 2) {
101 throttle = THROTTLE_FAST;
102 } else if (avail >= (mMaxFrames * 3) / 8) {
103 throttle = THROTTLE_NOMINAL;
104 } else if (avail >= mMaxFrames / 4) {
105 throttle = THROTTLE_SLOW;
106 } else {
107 throttle = THROTTLE_VERY_SLOW;
108 }
109 if (written > 0) {
110 // FIXME cache these values also
111 switch (throttle) {
112 case THROTTLE_VERY_FAST:
113 default:
114 ns = written * ( 500000000 / Format_sampleRate(mFormat));
115 break;
116 case THROTTLE_FAST:
117 ns = written * ( 750000000 / Format_sampleRate(mFormat));
118 break;
119 case THROTTLE_NOMINAL:
120 ns = written * (1000000000 / Format_sampleRate(mFormat));
121 break;
122 case THROTTLE_SLOW:
123 ns = written * (1100000000 / Format_sampleRate(mFormat));
124 break;
125 case THROTTLE_VERY_SLOW:
126 ns = written * (1250000000 / Format_sampleRate(mFormat));
127 break;
128 }
129 } else {
130 ns = mMaxFrames * (250000000 / Format_sampleRate(mFormat));
131 }
132 if (ns > 999999999) {
133 ns = 999999999;
134 }
135 struct timespec sleep;
136 sleep.tv_sec = 0;
137 sleep.tv_nsec = ns;
138 nanosleep(&sleep, NULL);
Glenn Kasten01066232012-02-27 11:50:44 -0800139 }
140 mFramesWritten += totalFramesWritten;
141 return totalFramesWritten;
142}
143
144} // namespace android