blob: bb9e1968ef6266d7055d1178395a3c2964fdd1d2 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstdint>
#include <cinttypes>
extern "C"{
#include <cutils/str_parms.h>
}
#include "common/libs/auto_resources/auto_resources.h"
#include "common/libs/threads/thunkers.h"
#include "guest/hals/audio/legacy/audio_hal.h"
#include "guest/hals/audio/legacy/vsoc_audio.h"
#include "guest/hals/audio/legacy/vsoc_audio_input_stream.h"
namespace cvd {
#if defined(AUDIO_DEVICE_API_VERSION_3_0)
static inline size_t GceAudioFrameSize(const audio_stream_in* s) {
return audio_stream_in_frame_size(s);
}
#elif defined(AUDIO_DEVICE_API_VERSION_2_0)
static inline size_t GceAudioFrameSize(const audio_stream_in* s) {
return audio_stream_frame_size(&s->common);
}
#else
static inline size_t GceAudioFrameSize(audio_stream_in* s) {
return audio_stream_frame_size(&s->common);
}
#endif
GceAudioInputStream::GceAudioInputStream(
cvd::GceAudio* dev, audio_devices_t devices, const audio_config& config)
: audio_stream_in(),
dev_(dev),
config_(config),
gain_(0.0),
device_(devices) {
common.get_sample_rate =
cvd::thunk<audio_stream, &GceAudioInputStream::GetSampleRate>;
common.set_sample_rate =
cvd::thunk<audio_stream, &GceAudioInputStream::SetSampleRate>;
common.get_buffer_size =
cvd::thunk<audio_stream, &GceAudioInputStream::GetBufferSize>;
common.get_channels =
cvd::thunk<audio_stream, &GceAudioInputStream::GetChannels>;
common.get_device = cvd::thunk<audio_stream, &GceAudioInputStream::GetDevice>;
common.set_device = cvd::thunk<audio_stream, &GceAudioInputStream::SetDevice>;
common.get_format = cvd::thunk<audio_stream, &GceAudioInputStream::GetFormat>;
common.set_format = cvd::thunk<audio_stream, &GceAudioInputStream::SetFormat>;
common.standby = cvd::thunk<audio_stream, &GceAudioInputStream::Standby>;
common.dump = cvd::thunk<audio_stream, &GceAudioInputStream::Dump>;
common.set_parameters = GceAudio::SetStreamParameters;
common.get_parameters =
cvd::thunk<audio_stream, &GceAudioInputStream::GetParameters>;
common.add_audio_effect =
cvd::thunk<audio_stream, &GceAudioInputStream::AddAudioEffect>;
common.remove_audio_effect = cvd::thunk<audio_stream,
&GceAudioInputStream::RemoveAudioEffect>;
set_gain = cvd::thunk<audio_stream_in, &GceAudioInputStream::SetGain>;
read = cvd::thunk<audio_stream_in,
&GceAudioInputStream::Read>;
get_input_frames_lost = cvd::thunk<audio_stream_in,
&GceAudioInputStream::GetInputFramesLost>;
frame_size_ = GceAudioFrameSize(this);
buffer_model_.reset(
new SimulatedInputBuffer(config_.sample_rate, GetBufferSize() /
frame_size_));
reported_lost_frames_ = 0;
}
gce_audio_message GceAudioInputStream::GetStreamDescriptor(
uint32_t stream_number, gce_audio_message::message_t event) {
gce_audio_message rval;
rval.message_type = event;
rval.stream_number = stream_number;
rval.frame_num = buffer_model_->GetCurrentItemNum();
rval.time_presented =
buffer_model_->GetLastUpdatedTime().SinceEpoch().GetTS();
rval.frame_rate = config_.sample_rate;
rval.channel_mask = config_.channel_mask;
rval.format = config_.format;
rval.frame_size = frame_size_;
return rval;
}
int GceAudioInputStream::Open(GceAudio* dev,
audio_io_handle_t /*handle*/,
audio_devices_t devices,
const audio_config& config,
GceAudioInputStream** stream_in) {
D("GceAudioInputStream::%s", __FUNCTION__);
*stream_in = new GceAudioInputStream(dev, devices, config);
return 0;
}
int GceAudioInputStream::SetFormat(audio_format_t format) {
config_.format = format;
frame_size_ = GceAudioFrameSize(this);
return 0;
}
int GceAudioInputStream::Dump(int fd) const {
D("GceAudioInputStream::%s", __FUNCTION__);
dprintf(
fd,
"\tInputSteam Dump:\n"
"\t\tsample rate: %u\n"
"\t\tbuffer size: %zu\n"
"\t\tchannel mask: %08x\n"
"\t\tformat: %d\n"
"\t\tdevice: %08x\n"
"\t\taudio dev: %p\n\n",
GetSampleRate(), GetBufferSize(),
GetChannels(), GetFormat(), device_, dev_);
return 0;
}
int GceAudioInputStream::SetSampleRate(uint32_t sample_rate) {
if (sample_rate != config_.sample_rate) {
config_.sample_rate = sample_rate;
buffer_model_.reset(
new SimulatedInputBuffer(sample_rate, GetBufferSize() / frame_size_));
reported_lost_frames_ = 0;
}
return 0;
}
char* GceAudioInputStream::GetParameters(const char* keys) const {
D("GceAudioInputStream::%s", __FUNCTION__);
if (keys) D("GceAudioInputStream::%s keys %s", __FUNCTION__, keys);
str_parms* query = str_parms_create_str(keys);
str_parms* reply = str_parms_create();
char value[256];
int ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING,
value, sizeof(value));
char* str;
if (ret >= 0) {
str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, device_);
str = strdup(str_parms_to_str(reply));
} else {
str = strdup(keys);
}
str_parms_destroy(query);
str_parms_destroy(reply);
return str;
}
ssize_t GceAudioInputStream::Read(void* buffer, size_t bytes) {
int64_t available = buffer_model_->RemoveFromInputBuffer(
bytes / frame_size_, false) * frame_size_;
ssize_t rval = available;
if ((rval != available) || (rval < 0)) {
ALOGE("GceAudioInputStream:%s got bad value from "
"RemoveFromInputBuffer %" PRId64, __FUNCTION__, available);
return -1;
}
memset(buffer, 0, rval);
return rval;
}
}