1 /*
2 * Copyright (c) 2021-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define HST_LOG_TAG "SdlAudioSinkPlugin"
17
18 #include "sdl_audio_sink_plugin.h"
19 #include <functional>
20 #include "foundation/cpp_ext/memory_ext.h"
21 #include "foundation/log.h"
22 #include "foundation/osal/utils/util.h"
23 #include "foundation/pre_defines.h"
24 #include "foundation/utils/constants.h"
25 #include "plugin/common/plugin_attr_desc.h"
26 #include "plugin/common/plugin_audio_tags.h"
27 #include "plugin/common/plugin_buffer.h"
28 #include "plugin/common/plugin_time.h"
29 #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"
30
31 namespace {
32 using namespace OHOS::Media::Plugin;
33 using namespace Sdl;
34 constexpr int MAX_AUDIO_FRAME_SIZE = 192000;
35 constexpr uint32_t DEFAULT_OUTPUT_CHANNELS = 2;
36 constexpr AudioChannelLayout DEFAULT_OUTPUT_CHANNEL_LAYOUT = AudioChannelLayout::STEREO;
37 std::function<void(void*, uint8_t*, int)> g_audioCallback;
38
RegisterAudioCallback(std::function<void (void *,uint8_t *,int)> callback)39 void RegisterAudioCallback(std::function<void(void*, uint8_t*, int)> callback)
40 {
41 g_audioCallback = std::move(callback);
42 }
SDLAudioCallback(void * userdata,uint8_t * stream,int len)43 void SDLAudioCallback(void* userdata, uint8_t* stream, int len) // NOLINT: void*
44 {
45 g_audioCallback(userdata, stream, len);
46 }
TranslateFormat(AudioSampleFormat format)47 AVSampleFormat TranslateFormat(AudioSampleFormat format)
48 {
49 switch (format) {
50 case AudioSampleFormat::U8:
51 return AV_SAMPLE_FMT_U8;
52 case AudioSampleFormat::U8P:
53 return AV_SAMPLE_FMT_U8P;
54 case AudioSampleFormat::F32:
55 return AV_SAMPLE_FMT_FLT;
56 case AudioSampleFormat::F32P:
57 return AV_SAMPLE_FMT_FLTP;
58 case AudioSampleFormat::F64:
59 return AV_SAMPLE_FMT_DBL;
60 case AudioSampleFormat::F64P:
61 return AV_SAMPLE_FMT_DBLP;
62 case AudioSampleFormat::S32:
63 return AV_SAMPLE_FMT_S32;
64 case AudioSampleFormat::S32P:
65 return AV_SAMPLE_FMT_S32P;
66 case AudioSampleFormat::S16:
67 return AV_SAMPLE_FMT_S16;
68 case AudioSampleFormat::S16P:
69 return AV_SAMPLE_FMT_S16P;
70 default:
71 return AV_SAMPLE_FMT_NONE;
72 }
73 }
74
IsPlanes(AudioSampleFormat format)75 bool IsPlanes(AudioSampleFormat format)
76 {
77 switch (format) {
78 case AudioSampleFormat::F32P:
79 case AudioSampleFormat::F64P:
80 case AudioSampleFormat::S32P:
81 case AudioSampleFormat::S16P:
82 return true;
83 default:
84 return false;
85 }
86 }
87
AudioSinkPluginCreator(const std::string & name)88 std::shared_ptr<AudioSinkPlugin> AudioSinkPluginCreator(const std::string& name)
89 {
90 return std::make_shared<SdlAudioSinkPlugin>(name);
91 }
92
SdlAudioRegister(const std::shared_ptr<Register> & reg)93 const Status SdlAudioRegister(const std::shared_ptr<Register>& reg)
94 {
95 AudioSinkPluginDef definition;
96 definition.name = "sdl_audio_sink";
97 definition.rank = 100; // 100
98 Capability cap(OHOS::Media::MEDIA_MIME_AUDIO_RAW);
99 cap.AppendDiscreteKeys<AudioSampleFormat>(
100 Capability::Key::AUDIO_SAMPLE_FORMAT,
101 {AudioSampleFormat::U8, AudioSampleFormat::U8P, AudioSampleFormat::S8, AudioSampleFormat::S8P,
102 AudioSampleFormat::U16, AudioSampleFormat::U16P, AudioSampleFormat::S16, AudioSampleFormat::S16P,
103 AudioSampleFormat::U32, AudioSampleFormat::U32P, AudioSampleFormat::S32, AudioSampleFormat::S32P,
104 AudioSampleFormat::F32, AudioSampleFormat::F32P, AudioSampleFormat::F64, AudioSampleFormat::F64P});
105 definition.inCaps.emplace_back(cap);
106 definition.creator = AudioSinkPluginCreator;
107 return reg->AddPlugin(definition);
108 }
109
__anonb2affe2c0202null110 PLUGIN_DEFINITION(SdlAudioSink, LicenseType::LGPL, SdlAudioRegister, [] {});
111 } // namespace
112
113 namespace OHOS {
114 namespace Media {
115 namespace Plugin {
116 namespace Sdl {
SdlAudioSinkPlugin(std::string name)117 SdlAudioSinkPlugin::SdlAudioSinkPlugin(std::string name)
118 : AudioSinkPlugin(std::move(name)),
119 volume_(SDL_MIX_MAXVOLUME)
120 {
121 }
Init()122 Status SdlAudioSinkPlugin::Init()
123 {
124 std::weak_ptr<SdlAudioSinkPlugin> weakPtr(shared_from_this());
125 RegisterAudioCallback([weakPtr](void* userdata, uint8_t* stream, int len) {
126 auto ptr = weakPtr.lock();
127 if (ptr) {
128 ptr->AudioCallback(userdata, stream, len);
129 }
130 });
131 return Status::OK;
132 }
133
Deinit()134 Status SdlAudioSinkPlugin::Deinit()
135 {
136 if (resample_) {
137 resample_.reset();
138 }
139 return Status::OK;
140 }
141
Prepare()142 Status SdlAudioSinkPlugin::Prepare()
143 {
144 MEDIA_LOG_I("SDL SINK Prepare enter...");
145 reSrcFfFmt_ = TranslateFormat(audioFormat_);
146 srcFrameSize_ = av_samples_get_buffer_size(nullptr, channels_, samplesPerFrame_, reSrcFfFmt_, 1);
147 rb = CppExt::make_unique<RingBuffer>(srcFrameSize_ * 10); // 最大缓存10帧
148 rb->Init();
149 if (reSrcFfFmt_ != reFfDestFmt_) {
150 needResample_ = true;
151 }
152 wantedSpec_.freq = sampleRate_;
153 wantedSpec_.format = AUDIO_S16SYS;
154 wantedSpec_.channels = channels_;
155 wantedSpec_.samples = samplesPerFrame_;
156 wantedSpec_.silence = 0;
157 wantedSpec_.callback = SDLAudioCallback;
158 if (SDL_OpenAudio(&wantedSpec_, nullptr) < 0) {
159 MEDIA_LOG_E("sdl cannot open audio with error: " PUBLIC_LOG_S, SDL_GetError());
160 return Status::ERROR_UNKNOWN;
161 }
162 if (bitsPerSample_ == 8 || bitsPerSample_ == 24) { // 8 24
163 needResample_ = true;
164 }
165 if (needResample_) {
166 resample_ = std::make_shared<Ffmpeg::Resample>();
167 Ffmpeg::ResamplePara resamplePara {
168 channels_,
169 sampleRate_,
170 bitsPerSample_,
171 static_cast<int64_t>(channelLayout_),
172 reSrcFfFmt_,
173 samplesPerFrame_,
174 reFfDestFmt_,
175 };
176 FALSE_RETURN_V_MSG(resample_->Init(resamplePara) == Status::OK, Status::ERROR_UNKNOWN, "Resample init error");
177 }
178 return Status::OK;
179 }
180
Reset()181 Status SdlAudioSinkPlugin::Reset()
182 {
183 if (resample_) {
184 resample_.reset();
185 }
186 return Status::OK;
187 }
188
Start()189 Status SdlAudioSinkPlugin::Start()
190 {
191 MEDIA_LOG_I("SDL SINK start...");
192 SDL_PauseAudio(0);
193 rb->SetActive(true);
194 return Status::OK;
195 }
196
Stop()197 Status SdlAudioSinkPlugin::Stop()
198 {
199 MEDIA_LOG_I("SDL SINK Stop...");
200 rb->SetActive(false);
201 SDL_PauseAudio(1);
202 Flush();
203 SDL_CloseAudio();
204 MEDIA_LOG_I("SDL SINK Stop end");
205 return Status::OK;
206 }
207
GetParameter(Tag tag,ValueType & value)208 Status SdlAudioSinkPlugin::GetParameter(Tag tag, ValueType& value)
209 {
210 switch (tag) {
211 case Tag::AUDIO_OUTPUT_CHANNELS: {
212 value = DEFAULT_OUTPUT_CHANNELS;
213 MEDIA_LOG_D("Get outputChannels: " PUBLIC_LOG_U32, DEFAULT_OUTPUT_CHANNELS);
214 break;
215 }
216 case Tag::AUDIO_OUTPUT_CHANNEL_LAYOUT: {
217 value = DEFAULT_OUTPUT_CHANNEL_LAYOUT;
218 MEDIA_LOG_D("Get outputChannelLayout: " PUBLIC_LOG_U64, DEFAULT_OUTPUT_CHANNEL_LAYOUT);
219 break;
220 }
221 default: {
222 MEDIA_LOG_W("receive one parameter with unconcern key: " PUBLIC_LOG_S, Tag2String(tag));
223 break;
224 }
225 }
226 return Status::OK;
227 }
228
SetParameter(Tag tag,const ValueType & value)229 Status SdlAudioSinkPlugin::SetParameter(Tag tag, const ValueType& value)
230 {
231 #define RETURN_ERROR_IF_CHECK_ERROR(typenames) \
232 if (!Plugin::Any::IsSameTypeWith<typenames>(value)) { \
233 return Status::ERROR_MISMATCHED_TYPE; \
234 }
235 MEDIA_LOG_I("SetParameter entered, key: " PUBLIC_LOG_S, Tag2String(tag));
236 switch (tag) {
237 case Tag::AUDIO_OUTPUT_CHANNELS: {
238 RETURN_ERROR_IF_CHECK_ERROR(uint32_t);
239 channels_ = Plugin::AnyCast<uint32_t>(value);
240 if (channels_ > DEFAULT_OUTPUT_CHANNELS) {
241 channels_ = DEFAULT_OUTPUT_CHANNELS;
242 }
243 MEDIA_LOG_D("Set outputChannels: " PUBLIC_LOG_U32, channels_);
244 break;
245 }
246 case Tag::AUDIO_SAMPLE_RATE:
247 RETURN_ERROR_IF_CHECK_ERROR(uint32_t);
248 sampleRate_ = Plugin::AnyCast<uint32_t>(value);
249 break;
250 case Tag::AUDIO_SAMPLE_PER_FRAME:
251 RETURN_ERROR_IF_CHECK_ERROR(uint32_t);
252 samplesPerFrame_ = Plugin::AnyCast<uint32_t>(value);
253 break;
254 case Tag::AUDIO_OUTPUT_CHANNEL_LAYOUT: {
255 RETURN_ERROR_IF_CHECK_ERROR(AudioChannelLayout);
256 auto chanLayout = Plugin::AnyCast<AudioChannelLayout>(value);
257 if (chanLayout == AudioChannelLayout::MONO) {
258 channelLayout_ = AV_CH_LAYOUT_MONO;
259 } else if (chanLayout == AudioChannelLayout::STEREO) {
260 channelLayout_ = AV_CH_LAYOUT_STEREO;
261 }
262 MEDIA_LOG_D("Set outputChannelLayout: " PUBLIC_LOG_U64, channelLayout_);
263 break;
264 }
265 case Tag::AUDIO_SAMPLE_FORMAT:
266 RETURN_ERROR_IF_CHECK_ERROR(AudioSampleFormat);
267 audioFormat_ = Plugin::AnyCast<AudioSampleFormat>(value);
268 break;
269 case Tag::BITS_PER_CODED_SAMPLE:
270 RETURN_ERROR_IF_CHECK_ERROR(uint32_t);
271 bitsPerSample_ = Plugin::AnyCast<uint32_t>(value);
272 break;
273 default: {
274 MEDIA_LOG_W("receive one parameter with unconcern key: " PUBLIC_LOG_S, Tag2String(tag));
275 break;
276 }
277 }
278 return Status::OK;
279 }
280
GetAllocator()281 std::shared_ptr<Allocator> SdlAudioSinkPlugin::GetAllocator()
282 {
283 return nullptr;
284 }
285
SetCallback(Callback * cb)286 Status SdlAudioSinkPlugin::SetCallback(Callback* cb)
287 {
288 UNUSED_VARIABLE(cb);
289 return Status::ERROR_UNIMPLEMENTED;
290 }
291
GetMute(bool & mute)292 Status SdlAudioSinkPlugin::GetMute(bool& mute)
293 {
294 UNUSED_VARIABLE(mute);
295 return Status::ERROR_UNIMPLEMENTED;
296 }
297
SetMute(bool mute)298 Status SdlAudioSinkPlugin::SetMute(bool mute)
299 {
300 UNUSED_VARIABLE(mute);
301 return Status::ERROR_UNIMPLEMENTED;
302 }
303
GetVolume(float & volume)304 Status SdlAudioSinkPlugin::GetVolume(float& volume)
305 {
306 UNUSED_VARIABLE(volume);
307 volume = volume_ * 1.0 / SDL_MIX_MAXVOLUME;
308 return Status::OK;
309 }
310
SetVolume(float volume)311 Status SdlAudioSinkPlugin::SetVolume(float volume)
312 {
313 UNUSED_VARIABLE(volume);
314 volume_ = static_cast<int>(volume * SDL_MIX_MAXVOLUME);
315 return Status::OK;
316 }
317
GetSpeed(float & speed)318 Status SdlAudioSinkPlugin::GetSpeed(float& speed)
319 {
320 UNUSED_VARIABLE(speed);
321 return Status::ERROR_UNIMPLEMENTED;
322 }
323
SetSpeed(float speed)324 Status SdlAudioSinkPlugin::SetSpeed(float speed)
325 {
326 UNUSED_VARIABLE(speed);
327 return Status::ERROR_UNIMPLEMENTED;
328 }
329
Pause()330 Status SdlAudioSinkPlugin::Pause()
331 {
332 MEDIA_LOG_I("Paused");
333 SDL_PauseAudio(1);
334 return Status::OK;
335 }
336
Resume()337 Status SdlAudioSinkPlugin::Resume()
338 {
339 MEDIA_LOG_I("Resume");
340 rb->SetActive(true);
341 SDL_PauseAudio(0);
342 return Status::OK;
343 }
344
GetLatency(uint64_t & nanoSec)345 Status SdlAudioSinkPlugin::GetLatency(uint64_t& nanoSec)
346 {
347 nanoSec = 100 * HST_MSECOND; // 100ms
348 return Status::OK;
349 }
350
GetFrameSize(size_t & size)351 Status SdlAudioSinkPlugin::GetFrameSize(size_t& size)
352 {
353 UNUSED_VARIABLE(size);
354 return Status::ERROR_UNIMPLEMENTED;
355 }
356
GetFrameCount(uint32_t & count)357 Status SdlAudioSinkPlugin::GetFrameCount(uint32_t& count)
358 {
359 UNUSED_VARIABLE(count);
360 return Status::ERROR_UNIMPLEMENTED;
361 }
362
Write(const std::shared_ptr<Buffer> & buffer)363 Status SdlAudioSinkPlugin::Write(const std::shared_ptr<Buffer>& buffer)
364 {
365 MEDIA_LOG_DD("SdlSink Write begin");
366 FALSE_RETURN_V_MSG_W(buffer != nullptr && !buffer->IsEmpty(), Status::OK, "Receive empty buffer.");
367 auto mem = buffer->GetMemory();
368 auto srcBuffer = mem->GetReadOnlyData();
369 auto destBuffer = const_cast<uint8_t*>(srcBuffer);
370 auto srcLength = mem->GetSize();
371 auto destLength = srcLength;
372 if (needResample_ && resample_) {
373 FALSE_LOG(resample_->Convert(srcBuffer, srcLength, destBuffer, destLength) == Status::OK);
374 }
375 MEDIA_LOG_DD("SdlSink Write before ring buffer");
376 rb->WriteBuffer(destBuffer, destLength);
377 MEDIA_LOG_DD("SdlSink Write end");
378 return Status::OK;
379 }
380
Flush()381 Status SdlAudioSinkPlugin::Flush()
382 {
383 SDL_ClearQueuedAudio(1);
384 rb->SetActive(false);
385 return Status::OK;
386 }
387
Drain()388 Status SdlAudioSinkPlugin::Drain()
389 {
390 MEDIA_LOG_I("Drain begin");
391 while (rb->GetSize()) {
392 OSAL::SleepFor(10); // 10
393 }
394 MEDIA_LOG_I("Drain end");
395 return Status::OK;
396 }
397
AudioCallback(void * userdata,uint8_t * stream,int len)398 void SdlAudioSinkPlugin::AudioCallback(void* userdata, uint8_t* stream, int len) // NOLINT: void*
399 {
400 UNUSED_VARIABLE(userdata);
401 MEDIA_LOG_DD("sdl audio callback begin");
402 if (mixCache_.capacity() < len) {
403 mixCache_.reserve(len);
404 }
405 auto realLen = rb->ReadBuffer(mixCache_.data(), len);
406 if (realLen == 0) {
407 MEDIA_LOG_DD("sdl audio callback end with 0");
408 return;
409 }
410 SDL_memset(stream, 0, len);
411 SDL_MixAudio(stream, mixCache_.data(), realLen, volume_);
412 SDL_PauseAudio(0);
413 MEDIA_LOG_DD("sdl audio callback end with " PUBLIC_LOG_ZU, realLen);
414 }
415 } // namespace Sdl
416 } // namespace Plugin
417 } // namespace Media
418 } // namespace OHOS