1 // Copyright (c) 202020 The Samsung 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.
5 #include "media/audio/tizen/capi_usb_audio_input_stream.h"
10 #include "base/functional/bind.h"
11 #include "base/logging.h"
12 #include "media/audio/tizen/audio_manager_capi.h"
14 #include <sound_manager_internal.h>
17 CapiUsbAudioInputStream::CapiUsbAudioInputStream(
18 AudioManagerCapi* audio_manager,
19 const std::string& device_name,
20 const AudioParameters& params)
21 : CapiAudioInputStream(audio_manager, params) {
23 device_name_ = device_name;
24 #if BUILDFLAG(IS_TIZEN_TV)
25 device_added_for_stream_routing_ = false;
26 device_list_ = nullptr;
27 sound_device_ = nullptr;
28 stream_info_ = nullptr;
32 CapiUsbAudioInputStream::~CapiUsbAudioInputStream() {
33 #if !BUILDFLAG(IS_TIZEN_TV)
39 void CapiUsbAudioInputStream::AudioStreamReadCB(audio_in_h handle,
42 CapiUsbAudioInputStream* inputStream =
43 static_cast<CapiUsbAudioInputStream*>(user_data);
45 inputStream->ReadAudioData();
48 bool CapiUsbAudioInputStream::OpenMic() {
51 #if BUILDFLAG(IS_TIZEN_TV)
52 // TODO(Girish): Register stream focus changed callback and take action
55 ret = sound_manager_get_device_list(SOUND_DEVICE_IO_DIRECTION_IN_MASK,
57 if (ret != SOUND_MANAGER_ERROR_NONE) {
58 LOG(ERROR) << "sound_manager_get_device_list falied. Err:" << ret;
63 int device_id = std::atoi(device_name_.c_str());
64 sound_device_h device;
65 sound_device_type_e device_type;
66 sound_stream_type_e stream_type = SOUND_STREAM_TYPE_MEDIA_EXTERNAL_ONLY;
68 while (!sound_manager_get_next_device(device_list_, &device)) {
71 if (sound_manager_get_device_id(device, &id)) {
72 LOG(ERROR) << "Failed to get device ID";
76 if (sound_manager_get_device_type(device, &device_type)) {
77 LOG(ERROR) << "Failed to get device TYPE";
81 if (device_id == id) {
82 sound_device_ = device;
83 if (device_type == SOUND_DEVICE_BUILTIN_MIC) {
84 stream_type = SOUND_STREAM_TYPE_MEDIA;
85 sound_manager_set_stream_preemptive_device(
86 stream_type, SOUND_DEVICE_IO_DIRECTION_IN, device_id);
92 if (sound_device_ == nullptr) {
93 LOG(ERROR) << "Sound device with the mentioned ID does not exist";
98 stream_info_ = nullptr;
100 ret = sound_manager_create_stream_information(stream_type, nullptr, nullptr,
102 if (ret != SOUND_MANAGER_ERROR_NONE) {
103 LOG(ERROR) << "sound_manager_create_stream_information failed. Err:" << ret;
108 if (device_type != SOUND_DEVICE_BUILTIN_MIC) {
109 ret = sound_manager_add_device_for_stream_routing(stream_info_,
111 if (ret != SOUND_MANAGER_ERROR_NONE) {
112 LOG(ERROR) << "sound_manager_add_device_for_stream_routing failed. Err:"
118 device_added_for_stream_routing_ = true;
119 ret = sound_manager_apply_stream_routing(stream_info_);
120 if (ret != SOUND_MANAGER_ERROR_NONE) {
121 LOG(ERROR) << "sound_manager_apply_stream_routing failed. Err:" << ret;
128 ret = audio_in_create(params_.sample_rate(), AUDIO_CHANNEL_STEREO,
129 AUDIO_SAMPLE_TYPE_S16_LE, &device_);
130 if (ret != AUDIO_IO_ERROR_NONE) {
131 LOG(ERROR) << "audio_in_create failed. Err:" << ret;
136 #if BUILDFLAG(IS_TIZEN_TV)
137 ret = audio_in_set_sound_stream_info(device_, stream_info_);
138 if (ret != SOUND_MANAGER_ERROR_NONE) {
139 LOG(ERROR) << "audio_in_set_sound_stream_info failed. Err:" << ret;
145 state_ = media::kIsOpened;
149 void CapiUsbAudioInputStream::StartMic() {
152 int ret = audio_in_set_stream_cb(device_, &AudioStreamReadCB, this);
153 if (ret != AUDIO_IO_ERROR_NONE) {
154 LOG(ERROR) << "audio_in_set_stream_cb failed. Err:" << ret;
156 callback_->OnError();
160 audio_worker_.Start();
163 ret = audio_in_prepare(device_);
164 if (ret != AUDIO_IO_ERROR_NONE) {
165 LOG(ERROR) << "Cannot prepare audio input. Err:" << ret;
167 callback_->OnError();
171 state_ = media::kIsStarted;
174 void CapiUsbAudioInputStream::StopMic() {
177 if (AUDIO_IO_ERROR_NONE != audio_in_unprepare(device_))
178 LOG(WARNING) << "Cannot unprepare audio input";
180 if (AUDIO_IO_ERROR_NONE != audio_in_unset_stream_cb(device_))
181 LOG(WARNING) << "Cannot unset audio input cb";
184 void CapiUsbAudioInputStream::CloseMic(bool success) {
185 state_ = media::kIsClosed;
187 #if BUILDFLAG(IS_TIZEN_TV)
188 sound_device_type_e device_type;
189 sound_manager_get_device_type(sound_device_, &device_type);
191 if (device_type == SOUND_DEVICE_BUILTIN_MIC) {
192 sound_manager_set_stream_preemptive_device(
193 SOUND_STREAM_TYPE_MEDIA, SOUND_DEVICE_IO_DIRECTION_IN,
194 SOUND_MANAGER_STREAM_NO_PREEMPTIVE_DEVICE);
197 if (device_added_for_stream_routing_) {
198 int ret = sound_manager_remove_device_for_stream_routing(stream_info_,
200 if (ret != SOUND_MANAGER_ERROR_NONE)
202 << "sound_manager_remove_device_for_stream_routing failed. Err:"
205 device_added_for_stream_routing_ = false;
207 sound_device_ = nullptr;
210 int ret = sound_manager_free_device_list(device_list_);
211 if (ret != SOUND_MANAGER_ERROR_NONE)
212 LOG(ERROR) << "sound_manager_free_device_list failed. Err:" << ret;
214 device_list_ = nullptr;
218 int ret = sound_manager_destroy_stream_information(stream_info_);
219 if (ret != SOUND_MANAGER_ERROR_NONE)
220 LOG(ERROR) << "sound_manager_destroy_stream_information failed. Err:"
223 stream_info_ = nullptr;
228 int ret = audio_in_destroy(device_);
229 if (ret != AUDIO_IO_ERROR_NONE)
230 LOG(WARNING) << "audio_in_destroy failed. Err:" << ret;
235 if (!success && callback_)
236 callback_->OnError();
239 void CapiUsbAudioInputStream::ReadAudioData() {
240 unsigned int bytes_read = 0;
241 const void* loc_buff = nullptr;
243 if (AUDIO_IO_ERROR_NONE != audio_in_peek(device_, &loc_buff, &bytes_read)) {
244 LOG(ERROR) << "audio_in_peek() failed";
246 callback_->OnError();
250 int number_of_frames =
251 bytes_read / params_.GetBytesPerFrame(kDefaultSampleFormat);
252 if (number_of_frames > fifo_.GetUnfilledFrames()) {
253 int increase_blocks_of_buffer =
254 (number_of_frames - fifo_.GetUnfilledFrames()) /
255 params_.frames_per_buffer() +
257 fifo_.IncreaseCapacity(increase_blocks_of_buffer);
260 fifo_.Push(loc_buff, number_of_frames,
261 SampleFormatToBytesPerChannel(kDefaultSampleFormat));
263 double normalized_volume = 0.0;
264 GetAgcVolume(&normalized_volume);
266 double hardware_delay_seconds =
267 static_cast<double>(params_.GetBufferDuration().InSeconds() * 2) *
270 while (fifo_.available_blocks()) {
271 const AudioBus* audio_bus = fifo_.Consume();
273 hardware_delay_seconds +=
274 static_cast<double>(fifo_.GetAvailableFrames()) / params_.sample_rate();
276 // To reduce latency run client CB from dedicated thread
278 // Need to copy data out if it runs in different thread
279 std::unique_ptr<AudioBus> audio_bus_copy =
280 AudioBus::Create(audio_bus->channels(), audio_bus->frames());
281 audio_bus->CopyTo(audio_bus_copy.get());
282 audio_worker_.task_runner()->PostTask(
284 base::BindOnce(&CapiUsbAudioInputStream::OnAudioIOData,
285 base::Unretained(this), std::move(audio_bus_copy),
286 hardware_delay_seconds, normalized_volume));
290 if (AUDIO_IO_ERROR_NONE != audio_in_drop(device_)) {
291 LOG(ERROR) << "audio_in_drop() failed";
293 callback_->OnError();