blob: 0b6d1a301b2b5107673c09ad7c24d0a49aab6f31 [file] [log] [blame]
Don Turnerca6f91a2017-09-05 14:52:39 +01001/*
2 * Copyright (C) 2016 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#include "oboe/Oboe.h"
18
Don Turner379e8e52017-11-29 15:49:29 +000019#include "opensles/AudioStreamBuffered.h"
Don Turnerca6f91a2017-09-05 14:52:39 +010020#include "common/AudioClock.h"
21
Don Turner3bf32ae2017-11-27 13:25:05 +000022namespace oboe {
23
Don Turnerca6f91a2017-09-05 14:52:39 +010024/*
Don Turner379e8e52017-11-29 15:49:29 +000025 * AudioStream with a FifoBuffer
Don Turnerca6f91a2017-09-05 14:52:39 +010026 */
Don Turner379e8e52017-11-29 15:49:29 +000027AudioStreamBuffered::AudioStreamBuffered(const AudioStreamBuilder &builder)
Phil Burk373e6462018-02-07 20:37:17 -080028 : AudioStream(builder) {
29}
30AudioStreamBuffered::~AudioStreamBuffered() {
31 delete mFifoBuffer;
Don Turnerca6f91a2017-09-05 14:52:39 +010032}
33
Phil Burk373e6462018-02-07 20:37:17 -080034Result AudioStreamBuffered::finishOpen() {
Don Turnerca6f91a2017-09-05 14:52:39 +010035 // If the caller does not provide a callback use our own internal
36 // callback that reads data from the FIFO.
Don Turnerd4b7f082017-12-01 13:51:54 +000037 if (getCallback() == nullptr) {
Phil Burk373e6462018-02-07 20:37:17 -080038 LOGD("AudioStreamBuffered(): new FifoBuffer(bytesPerFrame=%d", getBytesPerFrame());
39 // FIFO is configured with the same format and channels as the stream.
Don Turnerca6f91a2017-09-05 14:52:39 +010040 mFifoBuffer = new FifoBuffer(getBytesPerFrame(), 1024); // TODO size?
41 // Create a callback that reads from the FIFO
Don Turner056fe732017-12-04 13:59:22 +000042 mInternalCallback = std::unique_ptr<AudioStreamBufferedCallback>(new AudioStreamBufferedCallback(this));
Don Turnerd4b7f082017-12-01 13:51:54 +000043 mStreamCallback = mInternalCallback.get();
44 LOGD("AudioStreamBuffered(): mStreamCallback = %p", mStreamCallback);
Don Turnerca6f91a2017-09-05 14:52:39 +010045 }
Don Turner3bf32ae2017-11-27 13:25:05 +000046 return Result::OK;
Don Turnerca6f91a2017-09-05 14:52:39 +010047}
48
Phil Burk373e6462018-02-07 20:37:17 -080049// TODO: This method should return a tuple of Result,int32_t where the
50// 2nd return param is the frames written. Maybe not!
Don Turner379e8e52017-11-29 15:49:29 +000051int32_t AudioStreamBuffered::write(const void *buffer,
Phil Burk373e6462018-02-07 20:37:17 -080052 int32_t numFrames,
53 int64_t timeoutNanoseconds)
Don Turnerca6f91a2017-09-05 14:52:39 +010054{
Don Turner3bf32ae2017-11-27 13:25:05 +000055 int32_t result = 0;
Don Turnerca6f91a2017-09-05 14:52:39 +010056 uint8_t *source = (uint8_t *)buffer;
57 int32_t framesLeft = numFrames;
58 while(framesLeft > 0 && result >= 0) {
Phil Burk373e6462018-02-07 20:37:17 -080059 result = mFifoBuffer->write(source, framesLeft);
60 LOGD("AudioStreamBuffered::%s(): wrote %d / %d frames to FIFO, [0] = %f",
61 __func__, result, framesLeft, ((float *)source)[0]);
Don Turnerca6f91a2017-09-05 14:52:39 +010062 if (result > 0) {
63 source += mFifoBuffer->convertFramesToBytes(result);
64 incrementFramesWritten(result);
65 framesLeft -= result;
66 }
67 if (framesLeft > 0 && result >= 0) {
68 int64_t wakeTimeNanos = mFifoBuffer->getNextReadTime(getSampleRate());
69 // TODO use timeoutNanoseconds
70 AudioClock::sleepUntilNanoTime(wakeTimeNanos);
71 }
72 }
73 return result;
74}
75
Phil Burk373e6462018-02-07 20:37:17 -080076// Read from the FIFO that was written by the callback.
77int32_t AudioStreamBuffered::read(void *buffer,
78 int32_t numFrames,
79 int64_t timeoutNanoseconds)
80{
81 static int readCount = 0;
82 int32_t result = 0;
83 uint8_t *destination = (uint8_t *)buffer;
84 int32_t framesLeft = numFrames;
85 while(framesLeft > 0 && result >= 0) {
86 result = mFifoBuffer->read(destination, framesLeft);
87 LOGD("AudioStreamBuffered::%s(): read %d/%d frames from FIFO, #%d",
88 __func__, result, framesLeft, readCount);
89 if (result > 0) {
90 destination += mFifoBuffer->convertFramesToBytes(result);
91 incrementFramesRead(result);
92 framesLeft -= result;
93 readCount++;
94 }
95 if (framesLeft > 0 && result >= 0) {
96 // FIXME use proper timing model, borrow one from AAudio
97 // TODO use timeoutNanoseconds
98 AudioClock::sleepForNanos(4 * kNanosPerMillisecond);
99 }
100 }
101
102 return result;
103}
104
Don Turner379e8e52017-11-29 15:49:29 +0000105Result AudioStreamBuffered::setBufferSizeInFrames(int32_t requestedFrames)
Don Turnerca6f91a2017-09-05 14:52:39 +0100106{
107 if (mFifoBuffer != nullptr) {
108 if (requestedFrames > mFifoBuffer->getBufferCapacityInFrames()) {
109 requestedFrames = mFifoBuffer->getBufferCapacityInFrames();
110 }
111 mFifoBuffer->setThresholdFrames(requestedFrames);
Don Turner3bf32ae2017-11-27 13:25:05 +0000112 return Result::OK;
Don Turnerca6f91a2017-09-05 14:52:39 +0100113 } else {
Don Turner3bf32ae2017-11-27 13:25:05 +0000114 return Result::ErrorUnimplemented;
Don Turnerca6f91a2017-09-05 14:52:39 +0100115 }
116}
117
118
Don Turner379e8e52017-11-29 15:49:29 +0000119int32_t AudioStreamBuffered::getBufferSizeInFrames() const {
Don Turnerca6f91a2017-09-05 14:52:39 +0100120 if (mFifoBuffer != nullptr) {
121 return mFifoBuffer->getThresholdFrames();
122 } else {
Don Turner379e8e52017-11-29 15:49:29 +0000123 return AudioStream::getBufferSizeInFrames();
Don Turnerca6f91a2017-09-05 14:52:39 +0100124 }
125}
126
Don Turner379e8e52017-11-29 15:49:29 +0000127int32_t AudioStreamBuffered::getBufferCapacityInFrames() const {
Don Turnerca6f91a2017-09-05 14:52:39 +0100128 if (mFifoBuffer != nullptr) {
129 return mFifoBuffer->getBufferCapacityInFrames(); // Maybe set mBufferCapacity in constructor
130 } else {
Don Turner379e8e52017-11-29 15:49:29 +0000131 return AudioStream::getBufferCapacityInFrames();
Don Turnerca6f91a2017-09-05 14:52:39 +0100132 }
133}
Don Turner3bf32ae2017-11-27 13:25:05 +0000134
135} // namespace oboe