| // Copyright 2021 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "media/mojo/common/audio_data_s16_converter.h" | 
 |  | 
 | #include <memory> | 
 |  | 
 | #include "media/base/audio_buffer.h" | 
 | #include "media/base/audio_bus.h" | 
 | #include "media/base/audio_timestamp_helper.h" | 
 | #include "media/base/channel_mixer.h" | 
 | #include "media/mojo/mojom/media_types.mojom.h" | 
 |  | 
 | namespace media { | 
 |  | 
 | AudioDataS16Converter::AudioDataS16Converter() = default; | 
 | AudioDataS16Converter::~AudioDataS16Converter() = default; | 
 |  | 
 | mojom::AudioDataS16Ptr AudioDataS16Converter::ConvertToAudioDataS16( | 
 |     scoped_refptr<AudioBuffer> buffer, | 
 |     bool is_multichannel_supported) { | 
 |   DCHECK_GT(buffer->frame_count(), 0); | 
 |   DCHECK_GT(buffer->channel_count(), 0); | 
 |   DCHECK_GT(buffer->sample_rate(), 0); | 
 |  | 
 |   // If the audio is already in the interleaved signed int 16 format, directly | 
 |   // assign it to the buffer, unless it is multichannel when multichannel is | 
 |   // not supported. | 
 |   if (buffer->sample_format() == SampleFormat::kSampleFormatS16 && | 
 |       (buffer->channel_count() == 1 || is_multichannel_supported)) { | 
 |     auto signed_buffer = mojom::AudioDataS16::New(); | 
 |     signed_buffer->channel_count = buffer->channel_count(); | 
 |     signed_buffer->frame_count = buffer->frame_count(); | 
 |     signed_buffer->sample_rate = buffer->sample_rate(); | 
 |     int16_t* audio_data = reinterpret_cast<int16_t*>(buffer->channel_data()[0]); | 
 |     signed_buffer->data.assign( | 
 |         audio_data, | 
 |         audio_data + buffer->frame_count() * buffer->channel_count()); | 
 |     return signed_buffer; | 
 |   } | 
 |  | 
 |   CopyBufferToTempAudioBus(*buffer); | 
 |   return ConvertAudioBusToAudioDataS16Internal( | 
 |       *temp_audio_bus_, buffer->sample_rate(), buffer->channel_layout(), | 
 |       is_multichannel_supported); | 
 | } | 
 |  | 
 | mojom::AudioDataS16Ptr AudioDataS16Converter::ConvertToAudioDataS16( | 
 |     std::unique_ptr<AudioBus> audio_bus, | 
 |     int sample_rate, | 
 |     ChannelLayout channel_layout, | 
 |     bool is_multichannel_supported) { | 
 |   DCHECK_GT(audio_bus->frames(), 0); | 
 |   DCHECK_GT(audio_bus->channels(), 0); | 
 |   return ConvertAudioBusToAudioDataS16Internal( | 
 |       *audio_bus, sample_rate, channel_layout, is_multichannel_supported); | 
 | } | 
 |  | 
 | mojom::AudioDataS16Ptr | 
 | AudioDataS16Converter::ConvertAudioBusToAudioDataS16Internal( | 
 |     const AudioBus& audio_bus, | 
 |     int sample_rate, | 
 |     ChannelLayout channel_layout, | 
 |     bool is_multichannel_supported) { | 
 |   auto signed_buffer = mojom::AudioDataS16::New(); | 
 |   signed_buffer->channel_count = audio_bus.channels(); | 
 |   signed_buffer->frame_count = audio_bus.frames(); | 
 |   signed_buffer->sample_rate = sample_rate; | 
 |  | 
 |   // If multichannel audio is not supported, mix the channels into a monaural | 
 |   // channel before converting it. | 
 |   if (audio_bus.channels() > 1 && !is_multichannel_supported) { | 
 |     signed_buffer->channel_count = 1; | 
 |     ResetChannelMixerIfNeeded(audio_bus.frames(), channel_layout); | 
 |     signed_buffer->data.resize(audio_bus.frames()); | 
 |  | 
 |     channel_mixer_->Transform(&audio_bus, monaural_audio_bus_.get()); | 
 |     monaural_audio_bus_->ToInterleaved<SignedInt16SampleTypeTraits>( | 
 |         monaural_audio_bus_->frames(), &signed_buffer->data[0]); | 
 |  | 
 |     return signed_buffer; | 
 |   } | 
 |  | 
 |   signed_buffer->data.resize(audio_bus.frames() * audio_bus.channels()); | 
 |   audio_bus.ToInterleaved<SignedInt16SampleTypeTraits>(audio_bus.frames(), | 
 |                                                        &signed_buffer->data[0]); | 
 |  | 
 |   return signed_buffer; | 
 | } | 
 |  | 
 | void AudioDataS16Converter::CopyBufferToTempAudioBus( | 
 |     const AudioBuffer& buffer) { | 
 |   if (!temp_audio_bus_ || | 
 |       buffer.channel_count() != temp_audio_bus_->channels() || | 
 |       buffer.frame_count() != temp_audio_bus_->frames()) { | 
 |     temp_audio_bus_ = | 
 |         AudioBus::Create(buffer.channel_count(), buffer.frame_count()); | 
 |   } | 
 |  | 
 |   buffer.ReadFrames(buffer.frame_count(), | 
 |                     /* source_frame_offset */ 0, /* dest_frame_offset */ 0, | 
 |                     temp_audio_bus_.get()); | 
 | } | 
 |  | 
 | void AudioDataS16Converter::ResetChannelMixerIfNeeded( | 
 |     int frame_count, | 
 |     ChannelLayout channel_layout) { | 
 |   if (!monaural_audio_bus_ || frame_count != monaural_audio_bus_->frames()) { | 
 |     monaural_audio_bus_ = AudioBus::Create(1 /* channels */, frame_count); | 
 |   } | 
 |  | 
 |   if (channel_layout != channel_layout_) { | 
 |     channel_layout_ = channel_layout; | 
 |     channel_mixer_ = | 
 |         std::make_unique<ChannelMixer>(channel_layout, CHANNEL_LAYOUT_MONO); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace media |