1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "qemu-stream.h" 6 7#include <fbl/vector.h> 8 9namespace audio { 10namespace intel_hda { 11namespace codecs { 12 13static constexpr uint8_t UNITY_GAIN = 74; 14static const audio_stream_unique_id_t microphone_id = AUDIO_STREAM_UNIQUE_ID_BUILTIN_MICROPHONE; 15static const audio_stream_unique_id_t speaker_id = AUDIO_STREAM_UNIQUE_ID_BUILTIN_SPEAKERS; 16 17QemuStream::QemuStream(uint32_t stream_id, bool is_input, uint16_t converter_nid) 18 : IntelHDAStreamBase(stream_id, is_input), 19 converter_nid_(converter_nid) { 20 SetPersistentUniqueId(is_input ? microphone_id : speaker_id); 21} 22 23zx_status_t QemuStream::DisableConverterLocked(bool force_all) { 24 const CodecVerb DISABLE_CONVERTER_VERBS[] = { 25 SET_AMPLIFIER_GAIN_MUTE(true, 0, is_input(), !is_input()), 26 SET_CONVERTER_STREAM_CHAN(IHDA_INVALID_STREAM_TAG, 0), 27 }; 28 29 return RunCmdListLocked(DISABLE_CONVERTER_VERBS, countof(DISABLE_CONVERTER_VERBS), force_all); 30} 31 32zx_status_t QemuStream::RunCmdListLocked(const CodecVerb* list, size_t count, bool force_all) { 33 ZX_DEBUG_ASSERT(list); 34 35 zx_status_t total_res = ZX_OK; 36 for (size_t i = 0; i < count; ++i) { 37 const auto& verb = list[i]; 38 39 zx_status_t res = SendCodecCommandLocked(converter_nid_, verb, Ack::NO); 40 if ((res != ZX_OK) && !force_all) 41 return res; 42 43 if (total_res == ZX_OK) 44 total_res = res; 45 } 46 47 return total_res; 48} 49 50zx_status_t QemuStream::OnActivateLocked() { 51 fbl::Vector<audio_proto::FormatRange> supported_formats; 52 53 audio_proto::FormatRange range; 54 range.sample_formats = AUDIO_SAMPLE_FORMAT_16BIT; 55 range.min_channels = 1; 56 range.max_channels = 2; 57 range.min_frames_per_second = 16000; 58 range.max_frames_per_second = 96000; 59 range.flags = ASF_RANGE_FLAG_FPS_48000_FAMILY | ASF_RANGE_FLAG_FPS_44100_FAMILY; 60 61 fbl::AllocChecker ac; 62 supported_formats.push_back(range, &ac); 63 if (!ac.check()) 64 return ZX_ERR_NO_MEMORY; 65 66 SetSupportedFormatsLocked(fbl::move(supported_formats)); 67 68 return DisableConverterLocked(); 69} 70 71void QemuStream::OnDeactivateLocked() { 72 DisableConverterLocked(true); 73} 74 75zx_status_t QemuStream::BeginChangeStreamFormatLocked(const audio_proto::StreamSetFmtReq& fmt) { 76 return DisableConverterLocked(); 77} 78 79zx_status_t QemuStream::FinishChangeStreamFormatLocked(uint16_t encoded_fmt) { 80 const CodecVerb ENABLE_CONVERTER_VERBS[] = { 81 SET_CONVERTER_FORMAT(encoded_fmt), 82 SET_CONVERTER_STREAM_CHAN(dma_stream_tag(), 0), 83 SET_AMPLIFIER_GAIN_MUTE(false, UNITY_GAIN, is_input(), !is_input()), 84 }; 85 86 return RunCmdListLocked(ENABLE_CONVERTER_VERBS, countof(ENABLE_CONVERTER_VERBS)); 87} 88 89void QemuStream::OnGetStringLocked(const audio_proto::GetStringReq& req, 90 audio_proto::GetStringResp* out_resp) { 91 ZX_DEBUG_ASSERT(out_resp); 92 const char* str = nullptr; 93 94 switch (req.id) { 95 case AUDIO_STREAM_STR_ID_MANUFACTURER: 96 str = "QEMU"; 97 break; 98 99 case AUDIO_STREAM_STR_ID_PRODUCT: 100 str = is_input() ? "Builtin Microphone" : "Builtin Speakers"; 101 break; 102 103 default: 104 IntelHDAStreamBase::OnGetStringLocked(req, out_resp); 105 return; 106 } 107 108 int res = snprintf(reinterpret_cast<char*>(out_resp->str), sizeof(out_resp->str), "%s", 109 str ? str : "<unassigned>"); 110 ZX_DEBUG_ASSERT(res >= 0); 111 out_resp->result = ZX_OK; 112 out_resp->strlen = fbl::min<uint32_t>(res, sizeof(out_resp->str) - 1); 113 out_resp->id = req.id; 114} 115 116 117} // namespace codecs 118} // namespace intel_hda 119} // namespace audio 120