AudioStreamRecord.cpp revision e1ce491a25faf06fdeab00dd938515f71f28b095
1/*
2 * Copyright 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#define LOG_TAG "AudioStreamRecord"
18//#define LOG_NDEBUG 0
19#include <utils/Log.h>
20
21#include <stdint.h>
22#include <utils/String16.h>
23#include <media/AudioRecord.h>
24#include <oboe/OboeAudio.h>
25
26#include "AudioClock.h"
27#include "AudioStreamRecord.h"
28
29using namespace android;
30using namespace oboe;
31
32AudioStreamRecord::AudioStreamRecord()
33    : AudioStream()
34{
35}
36
37AudioStreamRecord::~AudioStreamRecord()
38{
39    const oboe_stream_state_t state = getState();
40    bool bad = !(state == OBOE_STREAM_STATE_UNINITIALIZED || state == OBOE_STREAM_STATE_CLOSED);
41    ALOGE_IF(bad, "stream not closed, in state %d", state);
42}
43
44oboe_result_t AudioStreamRecord::open(const AudioStreamBuilder& builder)
45{
46    oboe_result_t result = OBOE_OK;
47
48    result = AudioStream::open(builder);
49    if (result != OBOE_OK) {
50        return result;
51    }
52
53    // Try to create an AudioRecord
54
55    // TODO Support UNSPECIFIED in AudioTrack. For now, use stereo if unspecified.
56    int32_t samplesPerFrame = (getSamplesPerFrame() == OBOE_UNSPECIFIED)
57                              ? 2 : getSamplesPerFrame();
58    audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
59
60    AudioRecord::callback_t callback = NULL;
61    audio_input_flags_t flags = (audio_input_flags_t) AUDIO_INPUT_FLAG_NONE;
62
63    // TODO implement an unspecified Android format then use that.
64    audio_format_t format = (getFormat() == OBOE_UNSPECIFIED)
65            ? AUDIO_FORMAT_PCM_FLOAT
66            : OboeConvert_oboeToAndroidDataFormat(getFormat());
67
68    mAudioRecord = new AudioRecord(
69            AUDIO_SOURCE_DEFAULT,
70            getSampleRate(),
71            format,
72            channelMask,
73
74            mOpPackageName, // const String16& opPackageName TODO does not compile
75
76            0,    //    size_t frameCount = 0,
77            callback,
78            NULL, //    void* user = NULL,
79            0,    //    uint32_t notificationFrames = 0,
80            AUDIO_SESSION_ALLOCATE,
81            AudioRecord::TRANSFER_DEFAULT,
82            flags
83             //   int uid = -1,
84             //   pid_t pid = -1,
85             //   const audio_attributes_t* pAttributes = NULL
86             );
87
88    // Did we get a valid track?
89    status_t status = mAudioRecord->initCheck();
90    if (status != OK) {
91        close();
92        ALOGE("AudioStreamRecord::open(), initCheck() returned %d", status);
93        return OboeConvert_androidToOboeError(status);
94    }
95
96    // Get the actual rate.
97    setSampleRate(mAudioRecord->getSampleRate());
98    setSamplesPerFrame(mAudioRecord->channelCount());
99    setFormat(OboeConvert_androidToOboeDataFormat(mAudioRecord->format()));
100
101    setState(OBOE_STREAM_STATE_OPEN);
102
103    return OBOE_OK;
104}
105
106oboe_result_t AudioStreamRecord::close()
107{
108    // TODO add close() or release() to AudioRecord API then call it from here
109    if (getState() != OBOE_STREAM_STATE_CLOSED) {
110        mAudioRecord.clear();
111        setState(OBOE_STREAM_STATE_CLOSED);
112    }
113    return OBOE_OK;
114}
115
116oboe_result_t AudioStreamRecord::requestStart()
117{
118    if (mAudioRecord.get() == NULL) {
119        return OBOE_ERROR_INVALID_STATE;
120    }
121    // Get current position so we can detect when the track is playing.
122    status_t err = mAudioRecord->getPosition(&mPositionWhenStarting);
123    if (err != OK) {
124        return OboeConvert_androidToOboeError(err);
125    }
126    err = mAudioRecord->start();
127    if (err != OK) {
128        return OboeConvert_androidToOboeError(err);
129    } else {
130        setState(OBOE_STREAM_STATE_STARTING);
131    }
132    return OBOE_OK;
133}
134
135oboe_result_t AudioStreamRecord::requestPause()
136{
137    return OBOE_ERROR_UNIMPLEMENTED;
138}
139
140oboe_result_t AudioStreamRecord::requestFlush() {
141    return OBOE_ERROR_UNIMPLEMENTED;
142}
143
144oboe_result_t AudioStreamRecord::requestStop() {
145    if (mAudioRecord.get() == NULL) {
146        return OBOE_ERROR_INVALID_STATE;
147    }
148    setState(OBOE_STREAM_STATE_STOPPING);
149    mAudioRecord->stop();
150    return OBOE_OK;
151}
152
153oboe_result_t AudioStreamRecord::updateState()
154{
155    oboe_result_t result = OBOE_OK;
156    oboe_wrapping_frames_t position;
157    status_t err;
158    switch (getState()) {
159    // TODO add better state visibility to AudioRecord
160    case OBOE_STREAM_STATE_STARTING:
161        err = mAudioRecord->getPosition(&position);
162        if (err != OK) {
163            result = OboeConvert_androidToOboeError(err);
164        } else if (position != mPositionWhenStarting) {
165            setState(OBOE_STREAM_STATE_STARTED);
166        }
167        break;
168    case OBOE_STREAM_STATE_STOPPING:
169        if (mAudioRecord->stopped()) {
170            setState(OBOE_STREAM_STATE_STOPPED);
171        }
172        break;
173    default:
174        break;
175    }
176    return result;
177}
178
179oboe_result_t AudioStreamRecord::read(void *buffer,
180                                      oboe_size_frames_t numFrames,
181                                      oboe_nanoseconds_t timeoutNanoseconds)
182{
183    oboe_size_frames_t bytesPerFrame = getBytesPerFrame();
184    oboe_size_bytes_t numBytes;
185    oboe_result_t result = OboeConvert_framesToBytes(numFrames, bytesPerFrame, &numBytes);
186    if (result != OBOE_OK) {
187        return result;
188    }
189
190    // TODO add timeout to AudioRecord
191    bool blocking = (timeoutNanoseconds > 0);
192    ssize_t bytesRead = mAudioRecord->read(buffer, numBytes, blocking);
193    if (bytesRead == WOULD_BLOCK) {
194        return 0;
195    } else if (bytesRead < 0) {
196        return OboeConvert_androidToOboeError(bytesRead);
197    }
198    oboe_size_frames_t framesRead = (oboe_size_frames_t)(bytesRead / bytesPerFrame);
199    return (oboe_result_t) framesRead;
200}
201
202oboe_result_t AudioStreamRecord::setBufferSize(oboe_size_frames_t requestedFrames,
203                                             oboe_size_frames_t *actualFrames)
204{
205    *actualFrames = getBufferCapacity();
206    return OBOE_OK;
207}
208
209oboe_size_frames_t AudioStreamRecord::getBufferSize() const
210{
211    return getBufferCapacity(); // TODO implement in AudioRecord?
212}
213
214oboe_size_frames_t AudioStreamRecord::getBufferCapacity() const
215{
216    return static_cast<oboe_size_frames_t>(mAudioRecord->frameCount());
217}
218
219int32_t AudioStreamRecord::getXRunCount() const
220{
221    return OBOE_ERROR_UNIMPLEMENTED; // TODO implement when AudioRecord supports it
222}
223
224oboe_size_frames_t AudioStreamRecord::getFramesPerBurst() const
225{
226    return 192; // TODO add query to AudioRecord.cpp
227}
228
229// TODO implement getTimestamp
230
231