blob: ecf501f77635e6ed08a1772e3d4d475322d553af [file] [log] [blame]
// Copyright 2012 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/media/base/shell_data_source_reader.h"
#include "starboard/types.h"
namespace cobalt {
namespace media {
const int ShellDataSourceReader::kReadError = DataSource::kReadError;
ShellDataSourceReader::ShellDataSourceReader()
: data_source_(NULL),
blocking_read_event_(false, false),
file_size_(-1),
read_has_failed_(false),
last_bytes_read_(0) {}
ShellDataSourceReader::~ShellDataSourceReader() {}
void ShellDataSourceReader::SetDataSource(DataSource* data_source) {
DCHECK(data_source);
data_source_ = data_source;
}
// currently only single-threaded reads supported
int ShellDataSourceReader::BlockingRead(int64 position, int size, uint8* data) {
// read failures are unrecoverable, all subsequent reads will also fail
if (read_has_failed_) {
return kReadError;
}
// check bounds of read at or past EOF
if (file_size_ >= 0 && position >= file_size_) {
return 0;
}
int total_bytes_read = 0;
while (size > 0 && !read_has_failed_) {
{
base::AutoLock auto_lock(lock_);
if (!data_source_) {
break;
}
data_source_->Read(
position, size, data,
base::Bind(&ShellDataSourceReader::BlockingReadCompleted, this));
}
// wait for callback on read completion
blocking_read_event_.Wait();
if (last_bytes_read_ == DataSource::kReadError) {
// make all future reads fail
read_has_failed_ = true;
return kReadError;
}
DCHECK_LE(last_bytes_read_, size);
if (last_bytes_read_ > size) {
// make all future reads fail
read_has_failed_ = true;
return kReadError;
}
// Avoid entering an endless loop here.
if (last_bytes_read_ == 0) break;
total_bytes_read += last_bytes_read_;
position += last_bytes_read_;
size -= last_bytes_read_;
data += last_bytes_read_;
}
if (read_has_failed_) {
return kReadError;
}
return total_bytes_read;
}
void ShellDataSourceReader::Stop() {
if (data_source_) {
data_source_->Stop();
base::AutoLock auto_lock(lock_);
data_source_ = NULL;
}
}
void ShellDataSourceReader::BlockingReadCompleted(int bytes_read) {
last_bytes_read_ = bytes_read;
// wake up blocked thread
blocking_read_event_.Signal();
}
int64 ShellDataSourceReader::FileSize() {
if (file_size_ == -1) {
base::AutoLock auto_lock(lock_);
if (data_source_ && !data_source_->GetSize(&file_size_)) {
file_size_ = -1;
}
}
return file_size_;
}
} // namespace media
} // namespace cobalt