[M120 Migration][MM][WebRTC] Base implementation for webrtc video hole stream
[platform/framework/web/chromium-efl.git] / tizen_src / chromium_impl / media / audio / tizen / capi_usb_audio_input_stream.cc
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.
4
5 #include "media/audio/tizen/capi_usb_audio_input_stream.h"
6
7 #include <audio_io.h>
8 #include <sys/types.h>
9
10 #include "base/functional/bind.h"
11 #include "base/logging.h"
12 #include "media/audio/tizen/audio_manager_capi.h"
13
14 #include <sound_manager_internal.h>
15 namespace media {
16
17 CapiUsbAudioInputStream::CapiUsbAudioInputStream(
18     AudioManagerCapi* audio_manager,
19     const std::string& device_name,
20     const AudioParameters& params)
21     : CapiAudioInputStream(audio_manager, params) {
22   device_ = nullptr;
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;
29 #endif
30 }
31
32 CapiUsbAudioInputStream::~CapiUsbAudioInputStream() {
33 #if !BUILDFLAG(IS_TIZEN_TV)
34   DCHECK(!device_);
35 #endif
36 }
37
38 // static
39 void CapiUsbAudioInputStream::AudioStreamReadCB(audio_in_h handle,
40                                                 size_t nbytes,
41                                                 void* user_data) {
42   CapiUsbAudioInputStream* inputStream =
43       static_cast<CapiUsbAudioInputStream*>(user_data);
44   if (inputStream)
45     inputStream->ReadAudioData();
46 }
47
48 bool CapiUsbAudioInputStream::OpenMic() {
49   int ret;
50
51 #if BUILDFLAG(IS_TIZEN_TV)
52   // TODO(Girish): Register stream focus changed callback and take action
53   // accordingly.
54
55   ret = sound_manager_get_device_list(SOUND_DEVICE_IO_DIRECTION_IN_MASK,
56                                       &device_list_);
57   if (ret != SOUND_MANAGER_ERROR_NONE) {
58     LOG(ERROR) << "sound_manager_get_device_list falied. Err:" << ret;
59     CloseMic(false);
60     return false;
61   }
62
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;
67
68   while (!sound_manager_get_next_device(device_list_, &device)) {
69     int id;
70
71     if (sound_manager_get_device_id(device, &id)) {
72       LOG(ERROR) << "Failed to get device ID";
73       continue;
74     }
75
76     if (sound_manager_get_device_type(device, &device_type)) {
77       LOG(ERROR) << "Failed to get device TYPE";
78       continue;
79     }
80
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);
87       }
88       break;
89     }
90   }
91
92   if (sound_device_ == nullptr) {
93     LOG(ERROR) << "Sound device with the mentioned ID does not exist";
94     CloseMic(false);
95     return false;
96   }
97
98   stream_info_ = nullptr;
99
100   ret = sound_manager_create_stream_information(stream_type, nullptr, nullptr,
101                                                 &stream_info_);
102   if (ret != SOUND_MANAGER_ERROR_NONE) {
103     LOG(ERROR) << "sound_manager_create_stream_information failed. Err:" << ret;
104     CloseMic(false);
105     return false;
106   }
107
108   if (device_type != SOUND_DEVICE_BUILTIN_MIC) {
109     ret = sound_manager_add_device_for_stream_routing(stream_info_,
110                                                       sound_device_);
111     if (ret != SOUND_MANAGER_ERROR_NONE) {
112       LOG(ERROR) << "sound_manager_add_device_for_stream_routing failed. Err:"
113                  << ret;
114       CloseMic(false);
115       return false;
116     }
117
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;
122       CloseMic(false);
123       return false;
124     }
125   }
126 #endif
127
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;
132     CloseMic(false);
133     return false;
134   }
135
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;
140     CloseMic(false);
141     return false;
142   }
143 #endif
144
145   state_ = media::kIsOpened;
146   return true;
147 }
148
149 void CapiUsbAudioInputStream::StartMic() {
150   DCHECK(device_);
151
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;
155     if (callback_)
156       callback_->OnError();
157     return;
158   }
159
160   audio_worker_.Start();
161   StartAgc();
162
163   ret = audio_in_prepare(device_);
164   if (ret != AUDIO_IO_ERROR_NONE) {
165     LOG(ERROR) << "Cannot prepare audio input. Err:" << ret;
166     if (callback_)
167       callback_->OnError();
168     return;
169   }
170
171   state_ = media::kIsStarted;
172 }
173
174 void CapiUsbAudioInputStream::StopMic() {
175   DCHECK(device_);
176
177   if (AUDIO_IO_ERROR_NONE != audio_in_unprepare(device_))
178     LOG(WARNING) << "Cannot unprepare audio input";
179
180   if (AUDIO_IO_ERROR_NONE != audio_in_unset_stream_cb(device_))
181     LOG(WARNING) << "Cannot unset audio input cb";
182 }
183
184 void CapiUsbAudioInputStream::CloseMic(bool success) {
185   state_ = media::kIsClosed;
186
187 #if BUILDFLAG(IS_TIZEN_TV)
188   sound_device_type_e device_type;
189   sound_manager_get_device_type(sound_device_, &device_type);
190
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);
195   }
196
197   if (device_added_for_stream_routing_) {
198     int ret = sound_manager_remove_device_for_stream_routing(stream_info_,
199                                                              sound_device_);
200     if (ret != SOUND_MANAGER_ERROR_NONE)
201       LOG(ERROR)
202           << "sound_manager_remove_device_for_stream_routing failed. Err:"
203           << ret;
204
205     device_added_for_stream_routing_ = false;
206   }
207   sound_device_ = nullptr;
208
209   if (device_list_) {
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;
213
214     device_list_ = nullptr;
215   }
216
217   if (stream_info_) {
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:"
221                  << ret;
222
223     stream_info_ = nullptr;
224   }
225 #endif
226
227   if (device_) {
228     int ret = audio_in_destroy(device_);
229     if (ret != AUDIO_IO_ERROR_NONE)
230       LOG(WARNING) << "audio_in_destroy failed. Err:" << ret;
231
232     device_ = nullptr;
233   }
234
235   if (!success && callback_)
236     callback_->OnError();
237 }
238
239 void CapiUsbAudioInputStream::ReadAudioData() {
240   unsigned int bytes_read = 0;
241   const void* loc_buff = nullptr;
242
243   if (AUDIO_IO_ERROR_NONE != audio_in_peek(device_, &loc_buff, &bytes_read)) {
244     LOG(ERROR) << "audio_in_peek() failed";
245     if (callback_)
246       callback_->OnError();
247     return;
248   }
249
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() +
256         1;
257     fifo_.IncreaseCapacity(increase_blocks_of_buffer);
258   }
259
260   fifo_.Push(loc_buff, number_of_frames,
261              SampleFormatToBytesPerChannel(kDefaultSampleFormat));
262
263   double normalized_volume = 0.0;
264   GetAgcVolume(&normalized_volume);
265
266   double hardware_delay_seconds =
267       static_cast<double>(params_.GetBufferDuration().InSeconds() * 2) *
268       params_.channels();
269
270   while (fifo_.available_blocks()) {
271     const AudioBus* audio_bus = fifo_.Consume();
272
273     hardware_delay_seconds +=
274         static_cast<double>(fifo_.GetAvailableFrames()) / params_.sample_rate();
275
276     // To reduce latency run client CB from dedicated thread
277     if (callback_) {
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(
283           FROM_HERE,
284           base::BindOnce(&CapiUsbAudioInputStream::OnAudioIOData,
285                          base::Unretained(this), std::move(audio_bus_copy),
286                          hardware_delay_seconds, normalized_volume));
287     }
288   }
289
290   if (AUDIO_IO_ERROR_NONE != audio_in_drop(device_)) {
291     LOG(ERROR) << "audio_in_drop() failed";
292     if (callback_)
293       callback_->OnError();
294     return;
295   }
296 }
297
298 }  // namespace media