blob: 36595cf4325722277b45f9bcdd92f778a39d364c [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 "src/media/sounds/soundplayer/sound.h"
namespace soundplayer {
namespace {
constexpr uint64_t kNanosPerSecond = 1000000000;
const char kVmoName[] = "soundplayer decoded sound";
bool operator==(const fuchsia::media::AudioStreamType& lhs,
const fuchsia::media::AudioStreamType& rhs) {
return lhs.sample_format == rhs.sample_format && lhs.channels == rhs.channels &&
lhs.frames_per_second == rhs.frames_per_second;
}
} // namespace
Sound::Sound(zx::vmo vmo, uint64_t size, fuchsia::media::AudioStreamType stream_type)
: vmo_(std::move(vmo)), size_(size), stream_type_(std::move(stream_type)) {
FX_CHECK(vmo_.get_size(&vmo_size_) == ZX_OK);
}
const zx::vmo& Sound::LockForRead() {
FX_DCHECK(lock_count_ >= 0);
if (++lock_count_ == 1) {
ApplyLockForRead();
}
return vmo();
}
const zx::vmo& Sound::LockForWrite() {
FX_DCHECK(lock_count_ >= 0);
if (++lock_count_ == 1) {
ApplyLockForWrite();
}
return vmo();
}
void Sound::Unlock() {
FX_DCHECK(lock_count_ > 0);
if (--lock_count_ == 0) {
Removelock();
}
}
zx::duration Sound::duration() const {
return zx::nsec(kNanosPerSecond * size_) / stream_type_.channels / sizeof(int16_t) /
stream_type_.frames_per_second;
}
uint64_t Sound::frame_count() const { return size_ / frame_size(); }
uint32_t Sound::frame_size() const { return sample_size() * stream_type_.channels; }
uint32_t Sound::sample_size() const {
switch (stream_type_.sample_format) {
case fuchsia::media::AudioSampleFormat::UNSIGNED_8:
return sizeof(uint8_t);
case fuchsia::media::AudioSampleFormat::SIGNED_16:
return sizeof(int16_t);
case fuchsia::media::AudioSampleFormat::SIGNED_24_IN_32:
return sizeof(int32_t);
case fuchsia::media::AudioSampleFormat::FLOAT:
return sizeof(float);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// DiscardableSound definitions.
void DiscardableSound::ApplyLockForRead() {
FX_DCHECK(vmo());
zx_vmo_lock_state lock_state;
zx_status_t status =
vmo().op_range(ZX_VMO_OP_LOCK, 0, vmo_size(), &lock_state, sizeof(lock_state));
if (status != ZX_OK) {
FX_PLOGS(WARNING, status) << "Failed to lock vmo for read";
}
if (lock_state.discarded_size > 0) {
Restore();
}
}
void DiscardableSound::ApplyLockForWrite() {
FX_DCHECK(vmo());
zx_vmo_lock_state lock_state;
zx_status_t status =
vmo().op_range(ZX_VMO_OP_LOCK, 0, vmo_size(), &lock_state, sizeof(lock_state));
if (status != ZX_OK) {
FX_PLOGS(WARNING, status) << "Failed to lock vmo for write";
}
}
void DiscardableSound::Removelock() {
FX_DCHECK(vmo());
zx_status_t status = vmo().op_range(ZX_VMO_OP_UNLOCK, 0, vmo_size(), nullptr, 0);
if (status != ZX_OK) {
FX_PLOGS(WARNING, status) << "Failed to unlock vmo";
}
}
zx_status_t DiscardableSound::SetSize(size_t size_arg) {
if (vmo()) {
return size() == size_arg ? ZX_OK : ZX_ERR_INTERNAL;
}
zx_status_t status = zx::vmo::create(size_arg, ZX_VMO_DISCARDABLE, &vmo());
if (status != ZX_OK) {
FX_PLOGS(WARNING, status) << "Failed to create vmo";
return status;
}
status = vmo().set_property(ZX_PROP_NAME, kVmoName, strlen(kVmoName));
if (status != ZX_OK) {
FX_PLOGS(WARNING, status) << "Failed to set vmo name";
}
uint64_t vmo_size;
FX_CHECK(vmo().get_size(&vmo_size) == ZX_OK);
Sound::SetSize(size_arg, vmo_size);
return ZX_OK;
}
zx_status_t DiscardableSound::SetStreamType(fuchsia::media::AudioStreamType stream_type_arg) {
if (stream_type().frames_per_second != 0) {
return stream_type() == stream_type_arg ? ZX_OK : ZX_ERR_INTERNAL;
}
Sound::SetStreamType(std::move(stream_type_arg));
return ZX_OK;
}
void DiscardableSound::Restore() {
if (restore_callback_) {
restore_callback_();
}
}
} // namespace soundplayer