blob: 498263a37a566e67a192bed109c980b63e9df71b [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.
#ifndef SRC_MEDIA_SOUNDS_SOUNDPLAYER_SOUND_H_
#define SRC_MEDIA_SOUNDS_SOUNDPLAYER_SOUND_H_
#include <fuchsia/media/cpp/fidl.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/vmo.h>
#include <fbl/unique_fd.h>
namespace soundplayer {
// Base class for |UndiscardableSound| and |DiscardableSound|, both containers for sound that
// wrap a VMO containing raw LPCM audio content.
class Sound {
public:
virtual ~Sound() = default;
// Locks the sound VMO for reading, restoring its contents if it has been discarded. Locks may
// be nested arbitrarily (with a mix of |LockForRead| and |LockForWrite|). Only the outermost
// lock call has any effect aside from changing the nesting counter. There are no unexpected
// side effects, but, of course, if the intent is to read valid data from the VMO, the VMO
// should contain valid data.
const zx::vmo& LockForRead();
// Locks the sound VMO writing. If the VMO has been discarded, it is not restored. See the
// comment for |LockForRead| above.
const zx::vmo& LockForWrite();
// Unlocks the sound after |LockForRead| or |LockForWrite|.
void Unlock();
// Size of the sound in the VMO.
uint64_t size() const { return size_; }
// Size of the entire VMO.
uint64_t vmo_size() const { return vmo_size_; }
const fuchsia::media::AudioStreamType& stream_type() const { return stream_type_; }
zx::duration duration() const;
uint64_t frame_count() const;
uint32_t frame_size() const;
uint32_t sample_size() const;
protected:
// Constructs a |Sound| from a non-discardable VMO.
Sound(zx::vmo vmo, uint64_t size, fuchsia::media::AudioStreamType stream_type);
Sound() = default;
zx::vmo& vmo() { return vmo_; }
void SetSize(size_t size, size_t vmo_size) {
size_ = size;
vmo_size_ = vmo_size;
}
void SetStreamType(fuchsia::media::AudioStreamType stream_type) { stream_type_ = stream_type; }
// Applies a lock for reading on behalf of |LockForRead|, which handles the nesting counter.
virtual void ApplyLockForRead() = 0;
// Applies a lock for reading on behalf of |LockForWrite|, which handles the nesting counter.
virtual void ApplyLockForWrite() = 0;
// Removes a lock on behalf of |Unlock|, which handles the nesting counter.
virtual void Removelock() = 0;
private:
zx::vmo vmo_;
uint64_t size_ = 0;
uint64_t vmo_size_ = 0;
fuchsia::media::AudioStreamType stream_type_;
int32_t lock_count_ = 0;
};
// Container for raw LPCM sound in a VMO. An |UndiscardableSound| is created from an existing
// non-discardable, non-resizeable, VMO. |LockForRead|, |LockForWrite| and |Unlock| do nothing.
class UndiscardableSound : public Sound {
public:
// Constructs a |Sound| from a non-discardable VMO.
UndiscardableSound(zx::vmo vmo, uint64_t size, fuchsia::media::AudioStreamType stream_type)
: Sound(std::move(vmo), size, stream_type) {}
protected:
void ApplyLockForRead() override {}
void ApplyLockForWrite() override {}
void Removelock() override {}
};
// Container for raw LPCM sound in a VMO. A |DiscardableSound| is created from a file descriptor.
// Full initialization requires |SetSize|, |SetStreamType| and |SetRestoreCallback| to be called.
class DiscardableSound : public Sound {
public:
explicit DiscardableSound(fbl::unique_fd fd) : fd_(std::move(fd)) {}
DiscardableSound() = default;
~DiscardableSound() override = default;
int fd() const { return fd_.get(); }
// Sets the size and creates the VMO, or, if this method has already been called successfully,
// verifies that the given size matches the size as it was previously set. In the former case,
// an error is returned if the VMO creation fails. In the latter case, |ZX_ERR_INTERNAL| is
// returned if the sizes don't match.
//
// This method must be called once before |LockForRead| or |LockForWrite| are called.
zx_status_t SetSize(size_t size);
// Sets the stream type, or, if this method has already be called successfully, verifies that the
// given stream type matches the stream type as it was previously set. In the former case,
// |ZX_OK| is always returned. In the later case, |ZX_ERR_INTERNAL| is returned if the stream
// types don't match.
//
zx_status_t SetStreamType(fuchsia::media::AudioStreamType stream_type);
// Sets the callback that restores the VMO when |LockForRead| is called and the VMO has been
// discarded.
//
// If |LockForRead| is called before this method is called, no restoration will occur.
void SetRestoreCallback(fit::closure callback) {
FX_DCHECK(callback);
restore_callback_ = std::move(callback);
}
protected:
void ApplyLockForRead() override;
void ApplyLockForWrite() override;
void Removelock() override;
// Restores the locked VMO using the restore callback. This is protected (rather than private) to
// enable testing.
void Restore();
private:
fbl::unique_fd fd_;
fit::closure restore_callback_;
};
} // namespace soundplayer
#endif // SRC_MEDIA_SOUNDS_SOUNDPLAYER_SOUND_H_