blob: 0962977216e3a9d8d1910db533706f6b76781c51 [file] [log] [blame]
/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "cobalt/audio/audio_context.h"
#include "base/callback.h"
namespace cobalt {
namespace audio {
AudioContext::AudioContext()
: ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(
weak_this_(weak_ptr_factory_.GetWeakPtr())),
sample_rate_(0.0f),
current_time_(0.0f),
audio_lock_(new AudioLock()),
ALLOW_THIS_IN_INITIALIZER_LIST(
destination_(new AudioDestinationNode(this))),
next_callback_id_(0),
main_message_loop_(base::MessageLoopProxy::current()) {
DCHECK(main_message_loop_);
}
scoped_refptr<AudioBufferSourceNode> AudioContext::CreateBufferSource() {
DCHECK(main_message_loop_->BelongsToCurrentThread());
return scoped_refptr<AudioBufferSourceNode>(new AudioBufferSourceNode(this));
}
void AudioContext::DecodeAudioData(
script::EnvironmentSettings* settings,
const scoped_refptr<dom::ArrayBuffer>& audio_data,
const DecodeSuccessCallbackArg& success_handler) {
DCHECK(main_message_loop_->BelongsToCurrentThread());
scoped_ptr<DecodeCallbackInfo> info(
new DecodeCallbackInfo(settings, audio_data, this, success_handler));
DecodeAudioDataInternal(info.Pass());
}
void AudioContext::DecodeAudioData(
script::EnvironmentSettings* settings,
const scoped_refptr<dom::ArrayBuffer>& audio_data,
const DecodeSuccessCallbackArg& success_handler,
const DecodeErrorCallbackArg& error_handler) {
DCHECK(main_message_loop_->BelongsToCurrentThread());
scoped_ptr<DecodeCallbackInfo> info(new DecodeCallbackInfo(
settings, audio_data, this, success_handler, error_handler));
DecodeAudioDataInternal(info.Pass());
}
void AudioContext::DecodeAudioDataInternal(
scoped_ptr<DecodeCallbackInfo> info) {
DCHECK(main_message_loop_->BelongsToCurrentThread());
const int callback_id = next_callback_id_++;
CHECK(pending_decode_callbacks_.find(callback_id) ==
pending_decode_callbacks_.end());
const scoped_refptr<dom::ArrayBuffer>& audio_data = info->audio_data;
pending_decode_callbacks_[callback_id] = info.release();
AsyncAudioDecoder::DecodeFinishCallback decode_callback = base::Bind(
&AudioContext::DecodeFinish, base::Unretained(this), callback_id);
audio_decoder_.AsyncDecode(audio_data->data(), audio_data->byte_length(),
decode_callback);
}
// Success callback and error callback should be scheduled to run on the main
// thread's event loop.
void AudioContext::DecodeFinish(int callback_id, float sample_rate,
int32 number_of_frames,
int32 number_of_channels,
scoped_array<uint8> channels_data,
SampleType sample_type) {
if (!main_message_loop_->BelongsToCurrentThread()) {
main_message_loop_->PostTask(
FROM_HERE,
base::Bind(&AudioContext::DecodeFinish, weak_this_, callback_id,
sample_rate, number_of_frames, number_of_channels,
base::Passed(&channels_data), sample_type));
return;
}
DecodeCallbacks::iterator info_iterator =
pending_decode_callbacks_.find(callback_id);
DCHECK(info_iterator != pending_decode_callbacks_.end());
scoped_ptr<DecodeCallbackInfo> info(info_iterator->second);
pending_decode_callbacks_.erase(info_iterator);
if (channels_data) {
const scoped_refptr<AudioBuffer>& audio_buffer =
new AudioBuffer(info->env_settings, sample_rate, number_of_frames,
number_of_channels, channels_data.Pass(), sample_type);
info->success_callback.value().Run(audio_buffer);
} else if (info->error_callback) {
info->error_callback.value().value().Run();
}
}
} // namespace audio
} // namespace cobalt