1/*
2**
3** Copyright 2015, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "AudioFlinger"
19//#define LOG_NDEBUG 0
20
21#include <hardware/audio.h>
22#include <utils/Log.h>
23
24#include "AudioHwDevice.h"
25#include "AudioStreamOut.h"
26
27namespace android {
28
29// ----------------------------------------------------------------------------
30AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags)
31        : audioHwDev(dev)
32        , stream(NULL)
33        , flags(flags)
34        , mFramesWritten(0)
35        , mFramesWrittenAtStandby(0)
36        , mRenderPosition(0)
37        , mRateMultiplier(1)
38        , mHalFormatHasProportionalFrames(false)
39        , mHalFrameSize(0)
40{
41}
42
43audio_hw_device_t *AudioStreamOut::hwDev() const
44{
45    return audioHwDev->hwDevice();
46}
47
48status_t AudioStreamOut::getRenderPosition(uint64_t *frames)
49{
50    if (stream == NULL) {
51        return NO_INIT;
52    }
53
54    uint32_t halPosition = 0;
55    status_t status = stream->get_render_position(stream, &halPosition);
56    if (status != NO_ERROR) {
57        return status;
58    }
59
60    // Maintain a 64-bit render position using the 32-bit result from the HAL.
61    // This delta calculation relies on the arithmetic overflow behavior
62    // of integers. For example (100 - 0xFFFFFFF0) = 116.
63    uint32_t truncatedPosition = (uint32_t)mRenderPosition;
64    int32_t deltaHalPosition = (int32_t)(halPosition - truncatedPosition);
65    if (deltaHalPosition > 0) {
66        mRenderPosition += deltaHalPosition;
67    }
68    // Scale from HAL sample rate to application rate.
69    *frames = mRenderPosition / mRateMultiplier;
70
71    return status;
72}
73
74// return bottom 32-bits of the render position
75status_t AudioStreamOut::getRenderPosition(uint32_t *frames)
76{
77    uint64_t position64 = 0;
78    status_t status = getRenderPosition(&position64);
79    if (status == NO_ERROR) {
80        *frames = (uint32_t)position64;
81    }
82    return status;
83}
84
85status_t AudioStreamOut::getPresentationPosition(uint64_t *frames, struct timespec *timestamp)
86{
87    if (stream == NULL) {
88        return NO_INIT;
89    }
90
91    uint64_t halPosition = 0;
92    status_t status = stream->get_presentation_position(stream, &halPosition, timestamp);
93    if (status != NO_ERROR) {
94        return status;
95    }
96
97    // Adjust for standby using HAL rate frames.
98    // Only apply this correction if the HAL is getting PCM frames.
99    if (mHalFormatHasProportionalFrames) {
100        uint64_t adjustedPosition = (halPosition <= mFramesWrittenAtStandby) ?
101                0 : (halPosition - mFramesWrittenAtStandby);
102        // Scale from HAL sample rate to application rate.
103        *frames = adjustedPosition / mRateMultiplier;
104    } else {
105        // For offloaded MP3 and other compressed formats.
106        *frames = halPosition;
107    }
108
109    return status;
110}
111
112status_t AudioStreamOut::open(
113        audio_io_handle_t handle,
114        audio_devices_t devices,
115        struct audio_config *config,
116        const char *address)
117{
118    audio_stream_out_t *outStream;
119
120    audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
121                ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
122                : flags;
123
124    int status = hwDev()->open_output_stream(
125            hwDev(),
126            handle,
127            devices,
128            customFlags,
129            config,
130            &outStream,
131            address);
132    ALOGV("AudioStreamOut::open(), HAL returned "
133            " stream %p, sampleRate %d, Format %#x, "
134            "channelMask %#x, status %d",
135            outStream,
136            config->sample_rate,
137            config->format,
138            config->channel_mask,
139            status);
140
141    // Some HALs may not recognize AUDIO_FORMAT_IEC61937. But if we declare
142    // it as PCM then it will probably work.
143    if (status != NO_ERROR && config->format == AUDIO_FORMAT_IEC61937) {
144        struct audio_config customConfig = *config;
145        customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
146
147        status = hwDev()->open_output_stream(
148                hwDev(),
149                handle,
150                devices,
151                customFlags,
152                &customConfig,
153                &outStream,
154                address);
155        ALOGV("AudioStreamOut::open(), treat IEC61937 as PCM, status = %d", status);
156    }
157
158    if (status == NO_ERROR) {
159        stream = outStream;
160        mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format);
161        mHalFrameSize = audio_stream_out_frame_size(stream);
162    }
163
164    return status;
165}
166
167audio_format_t AudioStreamOut::getFormat() const
168{
169    return stream->common.get_format(&stream->common);
170}
171
172uint32_t AudioStreamOut::getSampleRate() const
173{
174    return stream->common.get_sample_rate(&stream->common);
175}
176
177audio_channel_mask_t AudioStreamOut::getChannelMask() const
178{
179    return stream->common.get_channels(&stream->common);
180}
181
182int AudioStreamOut::flush()
183{
184    ALOG_ASSERT(stream != NULL);
185    mRenderPosition = 0;
186    mFramesWritten = 0;
187    mFramesWrittenAtStandby = 0;
188    if (stream->flush != NULL) {
189        return stream->flush(stream);
190    }
191    return NO_ERROR;
192}
193
194int AudioStreamOut::standby()
195{
196    ALOG_ASSERT(stream != NULL);
197    mRenderPosition = 0;
198    mFramesWrittenAtStandby = mFramesWritten;
199    return stream->common.standby(&stream->common);
200}
201
202ssize_t AudioStreamOut::write(const void *buffer, size_t numBytes)
203{
204    ALOG_ASSERT(stream != NULL);
205    ssize_t bytesWritten = stream->write(stream, buffer, numBytes);
206    if (bytesWritten > 0 && mHalFrameSize > 0) {
207        mFramesWritten += bytesWritten / mHalFrameSize;
208    }
209    return bytesWritten;
210}
211
212} // namespace android
213