blob: dbbc860fa7e7ece843581cde4e3a0ffff7ff4203 [file] [log] [blame]
Phil Burk2355edb2016-12-26 13:54:02 -08001/*
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#define LOG_TAG "OboeService"
18//#define LOG_NDEBUG 0
19#include <utils/Log.h>
20
21#include "AudioClock.h"
22#include "AudioEndpointParcelable.h"
23
24#include "OboeServiceStreamBase.h"
25#include "OboeServiceStreamFakeHal.h"
26
27#include "FakeAudioHal.h"
28
29using namespace android;
30using namespace oboe;
31
32// HACK values for Marlin
33#define CARD_ID 0
34#define DEVICE_ID 19
35
36/**
37 * Construct the audio message queuues and message queues.
38 */
39
40OboeServiceStreamFakeHal::OboeServiceStreamFakeHal()
41 : OboeServiceStreamBase()
42 , mStreamId(nullptr)
43 , mPreviousFrameCounter(0)
44{
45}
46
47OboeServiceStreamFakeHal::~OboeServiceStreamFakeHal() {
48 ALOGD("OboeServiceStreamFakeHal::~OboeServiceStreamFakeHal() call close()");
49 close();
50}
51
52oboe_result_t OboeServiceStreamFakeHal::open(oboe::OboeStreamRequest &request,
53 oboe::OboeStreamConfiguration &configuration) {
54 // Open stream on HAL and pass information about the ring buffer to the client.
55 mmap_buffer_info mmapInfo;
56 oboe_result_t error;
57
58 // Open HAL
59 error = fake_hal_open(CARD_ID, DEVICE_ID, &mStreamId);
60 if(error < 0) {
61 ALOGE("Could not open card %d, device %d", CARD_ID, DEVICE_ID);
62 return error;
63 }
64
65 // Get information about the shared audio buffer.
66 error = fake_hal_get_mmap_info(mStreamId, &mmapInfo);
67 if (error < 0) {
68 ALOGE("fake_hal_get_mmap_info returned %d", error);
69 fake_hal_close(mStreamId);
70 mStreamId = nullptr;
71 return error;
72 }
73 mHalFileDescriptor = mmapInfo.fd;
74 mFramesPerBurst = mmapInfo.burst_size_in_frames;
75 mCapacityInFrames = mmapInfo.buffer_capacity_in_frames;
76 mCapacityInBytes = mmapInfo.buffer_capacity_in_bytes;
77 mSampleRate = mmapInfo.sample_rate;
78 mBytesPerFrame = mmapInfo.channel_count * sizeof(int16_t); // FIXME based on data format
79 ALOGD("OboeServiceStreamFakeHal::open() mmapInfo.burst_size_in_frames = %d",
80 mmapInfo.burst_size_in_frames);
81 ALOGD("OboeServiceStreamFakeHal::open() mmapInfo.buffer_capacity_in_frames = %d",
82 mmapInfo.buffer_capacity_in_frames);
83 ALOGD("OboeServiceStreamFakeHal::open() mmapInfo.buffer_capacity_in_bytes = %d",
84 mmapInfo.buffer_capacity_in_bytes);
85
86 // Fill in OboeStreamConfiguration
87 configuration.setSampleRate(mSampleRate);
88 configuration.setSamplesPerFrame(mmapInfo.channel_count);
89 configuration.setAudioFormat(OBOE_AUDIO_FORMAT_PCM16);
90 return OBOE_OK;
91}
92
93/**
94 * Get an immutable description of the in-memory queues
95 * used to communicate with the underlying HAL or Service.
96 */
97oboe_result_t OboeServiceStreamFakeHal::getDescription(AudioEndpointParcelable &parcelable) {
98 // Gather information on the message queue.
99 mUpMessageQueue->fillParcelable(parcelable,
100 parcelable.mUpMessageQueueParcelable);
101
102 // Gather information on the data queue.
103 // TODO refactor into a SharedRingBuffer?
104 int fdIndex = parcelable.addFileDescriptor(mHalFileDescriptor, mCapacityInBytes);
105 parcelable.mDownDataQueueParcelable.setupMemory(fdIndex, 0, mCapacityInBytes);
106 parcelable.mDownDataQueueParcelable.setBytesPerFrame(mBytesPerFrame);
107 parcelable.mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst);
108 parcelable.mDownDataQueueParcelable.setCapacityInFrames(mCapacityInFrames);
109 return OBOE_OK;
110}
111
112/**
113 * Start the flow of data.
114 */
115oboe_result_t OboeServiceStreamFakeHal::start() {
116 if (mStreamId == nullptr) return OBOE_ERROR_NULL;
117 oboe_result_t result = fake_hal_start(mStreamId);
118 sendServiceEvent(OBOE_SERVICE_EVENT_STARTED);
119 mState = OBOE_STREAM_STATE_STARTED;
120 return result;
121}
122
123/**
124 * Stop the flow of data such that start() can resume with loss of data.
125 */
126oboe_result_t OboeServiceStreamFakeHal::pause() {
127 if (mStreamId == nullptr) return OBOE_ERROR_NULL;
128 sendCurrentTimestamp();
129 oboe_result_t result = fake_hal_pause(mStreamId);
130 sendServiceEvent(OBOE_SERVICE_EVENT_PAUSED);
131 mState = OBOE_STREAM_STATE_PAUSED;
132 mFramesRead.reset32();
133 ALOGD("OboeServiceStreamFakeHal::pause() sent OBOE_SERVICE_EVENT_PAUSED");
134 return result;
135}
136
137/**
138 * Discard any data held by the underlying HAL or Service.
139 */
140oboe_result_t OboeServiceStreamFakeHal::flush() {
141 if (mStreamId == nullptr) return OBOE_ERROR_NULL;
142 // TODO how do we flush an MMAP/NOIRQ buffer? sync pointers?
143 ALOGD("OboeServiceStreamFakeHal::pause() send OBOE_SERVICE_EVENT_FLUSHED");
144 sendServiceEvent(OBOE_SERVICE_EVENT_FLUSHED);
145 mState = OBOE_STREAM_STATE_FLUSHED;
146 return OBOE_OK;
147}
148
149oboe_result_t OboeServiceStreamFakeHal::close() {
150 oboe_result_t result = OBOE_OK;
151 if (mStreamId != nullptr) {
152 result = fake_hal_close(mStreamId);
153 mStreamId = nullptr;
154 }
155 return result;
156}
157
158void OboeServiceStreamFakeHal::sendCurrentTimestamp() {
159 int frameCounter = 0;
160 int error = fake_hal_get_frame_counter(mStreamId, &frameCounter);
161 if (error < 0) {
162 ALOGE("OboeServiceStreamFakeHal::sendCurrentTimestamp() error %d",
163 error);
164 } else if (frameCounter != mPreviousFrameCounter) {
165 OboeServiceMessage command;
166 command.what = OboeServiceMessage::code::TIMESTAMP;
167 mFramesRead.update32(frameCounter);
168 command.timestamp.position = mFramesRead.get();
169 ALOGV("OboeServiceStreamFakeHal::sendCurrentTimestamp() HAL frames = %d, pos = %d",
170 frameCounter, (int)mFramesRead.get());
171 command.timestamp.timestamp = AudioClock::getNanoseconds();
172 mUpMessageQueue->getFifoBuffer()->write(&command, 1);
173 mPreviousFrameCounter = frameCounter;
174 }
175}
176
177void OboeServiceStreamFakeHal::tickle() {
178 if (mStreamId != nullptr) {
179 switch (mState) {
180 case OBOE_STREAM_STATE_STARTING:
181 case OBOE_STREAM_STATE_STARTED:
182 case OBOE_STREAM_STATE_PAUSING:
183 case OBOE_STREAM_STATE_STOPPING:
184 sendCurrentTimestamp();
185 break;
186 default:
187 break;
188 }
189 }
190}
191