2024-03-05 20:49:07 +00:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2022 suyu Emulator Project
|
2022-07-16 22:48:45 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2022-08-01 01:58:13 +00:00
|
|
|
#include <chrono>
|
|
|
|
#include <memory>
|
|
|
|
#include <optional>
|
2022-07-16 22:48:45 +00:00
|
|
|
#include <span>
|
|
|
|
|
|
|
|
#include "audio_core/common/common.h"
|
|
|
|
#include "audio_core/sink/sink.h"
|
2023-05-23 13:45:54 +00:00
|
|
|
#include "common/scratch_buffer.h"
|
2022-07-16 22:48:45 +00:00
|
|
|
#include "core/hle/service/audio/errors.h"
|
|
|
|
|
|
|
|
namespace Core {
|
|
|
|
class System;
|
2022-08-01 01:58:13 +00:00
|
|
|
namespace Timing {
|
|
|
|
struct EventType;
|
|
|
|
} // namespace Timing
|
|
|
|
} // namespace Core
|
2022-07-16 22:48:45 +00:00
|
|
|
|
2024-01-12 14:35:08 +00:00
|
|
|
namespace Kernel {
|
|
|
|
class KProcess;
|
|
|
|
} // namespace Kernel
|
|
|
|
|
2022-07-16 22:48:45 +00:00
|
|
|
namespace AudioCore {
|
2022-08-01 01:58:13 +00:00
|
|
|
|
2022-07-16 22:48:45 +00:00
|
|
|
namespace Sink {
|
|
|
|
class SinkStream;
|
|
|
|
struct SinkBuffer;
|
|
|
|
} // namespace Sink
|
|
|
|
|
|
|
|
struct AudioBuffer;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Represents an input or output device stream for audio in and audio out (not used for render).
|
|
|
|
**/
|
|
|
|
class DeviceSession {
|
|
|
|
public:
|
|
|
|
explicit DeviceSession(Core::System& system);
|
|
|
|
~DeviceSession();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize this device session.
|
|
|
|
*
|
|
|
|
* @param name - Name of this device.
|
|
|
|
* @param sample_format - Sample format for this device's output.
|
|
|
|
* @param channel_count - Number of channels for this device (2 or 6).
|
|
|
|
* @param session_id - This session's id.
|
2024-01-12 14:35:08 +00:00
|
|
|
* @param handle - Process handle for this device session.
|
2022-07-16 22:48:45 +00:00
|
|
|
* @param applet_resource_user_id - Applet resource user id for this device session (unused).
|
|
|
|
* @param type - Type of this stream (Render, In, Out).
|
|
|
|
* @return Result code for this call.
|
|
|
|
*/
|
|
|
|
Result Initialize(std::string_view name, SampleFormat sample_format, u16 channel_count,
|
2024-01-12 14:35:08 +00:00
|
|
|
size_t session_id, Kernel::KProcess* handle, u64 applet_resource_user_id,
|
2022-07-16 22:48:45 +00:00
|
|
|
Sink::StreamType type);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finalize this device session.
|
|
|
|
*/
|
|
|
|
void Finalize();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Append audio buffers to this device session to be played back.
|
|
|
|
*
|
|
|
|
* @param buffers - The buffers to play.
|
|
|
|
*/
|
2023-05-23 13:45:54 +00:00
|
|
|
void AppendBuffers(std::span<const AudioBuffer> buffers);
|
2022-07-16 22:48:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* (Audio In only) Pop samples from the backend, and write them back to this buffer's address.
|
|
|
|
*
|
|
|
|
* @param buffer - The buffer to write to.
|
|
|
|
*/
|
2022-09-16 13:29:28 +00:00
|
|
|
void ReleaseBuffer(const AudioBuffer& buffer) const;
|
2022-07-16 22:48:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if the buffer for the given tag has been consumed by the backend.
|
|
|
|
*
|
2022-09-13 17:50:39 +00:00
|
|
|
* @param buffer - the buffer to check.
|
|
|
|
*
|
2022-07-16 22:48:45 +00:00
|
|
|
* @return true if the buffer has been consumed, otherwise false.
|
|
|
|
*/
|
2022-09-16 13:29:28 +00:00
|
|
|
bool IsBufferConsumed(const AudioBuffer& buffer) const;
|
2022-07-16 22:48:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Start this device session, starting the backend stream.
|
|
|
|
*/
|
|
|
|
void Start();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop this device session, stopping the backend stream.
|
|
|
|
*/
|
|
|
|
void Stop();
|
|
|
|
|
2022-12-16 16:01:35 +00:00
|
|
|
/**
|
|
|
|
* Clear out the underlying audio buffers in the backend stream.
|
|
|
|
*/
|
|
|
|
void ClearBuffers();
|
|
|
|
|
2022-07-16 22:48:45 +00:00
|
|
|
/**
|
|
|
|
* Set this device session's volume.
|
|
|
|
*
|
|
|
|
* @param volume - New volume for this session.
|
|
|
|
*/
|
|
|
|
void SetVolume(f32 volume) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get this device session's total played sample count.
|
|
|
|
*
|
|
|
|
* @return Samples played by this session.
|
|
|
|
*/
|
|
|
|
u64 GetPlayedSampleCount() const;
|
|
|
|
|
2022-08-01 01:58:13 +00:00
|
|
|
/*
|
|
|
|
* CoreTiming callback to increment played_sample_count over time.
|
|
|
|
*/
|
|
|
|
std::optional<std::chrono::nanoseconds> ThreadFunc();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the size of the ring buffer.
|
|
|
|
*/
|
|
|
|
void SetRingSize(u32 ring_size);
|
|
|
|
|
2022-07-16 22:48:45 +00:00
|
|
|
private:
|
|
|
|
/// System
|
|
|
|
Core::System& system;
|
|
|
|
/// Output sink this device will use
|
|
|
|
Sink::Sink* sink{};
|
|
|
|
/// The backend stream for this device session to send samples to
|
|
|
|
Sink::SinkStream* stream{};
|
|
|
|
/// Name of this device session
|
|
|
|
std::string name{};
|
|
|
|
/// Type of this device session (render/in/out)
|
|
|
|
Sink::StreamType type{};
|
|
|
|
/// Sample format for this device.
|
|
|
|
SampleFormat sample_format{SampleFormat::PcmInt16};
|
|
|
|
/// Channel count for this device session
|
|
|
|
u16 channel_count{};
|
|
|
|
/// Session id of this device session
|
|
|
|
size_t session_id{};
|
2024-01-12 14:35:08 +00:00
|
|
|
/// Process handle of device memory owner
|
|
|
|
Kernel::KProcess* handle{};
|
2022-07-16 22:48:45 +00:00
|
|
|
/// Applet resource user id of this device session
|
|
|
|
u64 applet_resource_user_id{};
|
|
|
|
/// Total number of samples played by this device session
|
2022-08-01 01:58:13 +00:00
|
|
|
std::atomic<u64> played_sample_count{};
|
|
|
|
/// Event increasing the played sample count every 5ms
|
|
|
|
std::shared_ptr<Core::Timing::EventType> thread_event;
|
2022-07-16 22:48:45 +00:00
|
|
|
/// Is this session initialised?
|
|
|
|
bool initialized{};
|
2023-05-23 13:45:54 +00:00
|
|
|
/// Temporary sample buffer
|
|
|
|
Common::ScratchBuffer<s16> tmp_samples{};
|
2022-07-16 22:48:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace AudioCore
|