skyline/app/src/main/cpp/skyline/services/audio/IAudioOut.cpp

85 lines
3.9 KiB
C++

// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <kernel/types/KProcess.h>
#include "IAudioOut.h"
namespace skyline::service::audio {
IAudioOut::IAudioOut(const DeviceState &state, ServiceManager &manager, const u8 channelCount, const u32 sampleRate) : sampleRate(sampleRate), channelCount(channelCount), releaseEvent(std::make_shared<type::KEvent>(state)), BaseService(state, manager, Service::audio_IAudioOut, "audio:IAudioOut", {
{0x0, SFUNC(IAudioOut::GetAudioOutState)},
{0x1, SFUNC(IAudioOut::StartAudioOut)},
{0x2, SFUNC(IAudioOut::StopAudioOut)},
{0x3, SFUNC(IAudioOut::AppendAudioOutBuffer)},
{0x4, SFUNC(IAudioOut::RegisterBufferEvent)},
{0x5, SFUNC(IAudioOut::GetReleasedAudioOutBuffer)},
{0x6, SFUNC(IAudioOut::ContainsAudioOutBuffer)}
}) {
track = state.audio->OpenTrack(channelCount, constant::SampleRate, [this]() { this->releaseEvent->Signal(); });
}
IAudioOut::~IAudioOut() {
state.audio->CloseTrack(track);
}
void IAudioOut::GetAudioOutState(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
response.Push(static_cast<u32>(track->playbackState));
}
void IAudioOut::StartAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
state.logger->Debug("IAudioOut: Start playback");
track->Start();
}
void IAudioOut::StopAudioOut(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
state.logger->Debug("IAudioOut: Stop playback");
track->Stop();
}
void IAudioOut::AppendAudioOutBuffer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
struct Data {
u64 nextBufferPtr;
u64 sampleBufferPtr;
u64 sampleCapacity;
u64 sampleSize;
u64 sampleOffset;
} data = state.process->GetObject<Data>(request.inputBuf.at(0).address);
auto tag = request.Pop<u64>();
state.logger->Debug("IAudioOut: Appending buffer with address: 0x{:X}, size: 0x{:X}", data.sampleBufferPtr, data.sampleSize);
if (sampleRate != constant::SampleRate) {
tmpSampleBuffer.resize(data.sampleSize / sizeof(i16));
state.process->ReadMemory(tmpSampleBuffer.data(), data.sampleBufferPtr, data.sampleSize);
resampler.ResampleBuffer(tmpSampleBuffer, static_cast<double>(sampleRate) / constant::SampleRate, channelCount);
track->AppendBuffer(tag, tmpSampleBuffer);
} else {
track->AppendBuffer(tag, state.process->GetPointer<i16>(data.sampleBufferPtr), data.sampleSize);
}
}
void IAudioOut::RegisterBufferEvent(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto handle = state.process->InsertItem(releaseEvent);
state.logger->Debug("IAudioOut: Buffer Release Event Handle: 0x{:X}", handle);
response.copyHandles.push_back(handle);
}
void IAudioOut::GetReleasedAudioOutBuffer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto maxCount = static_cast<u32>(request.outputBuf.at(0).size >> 3);
std::vector<u64> releasedBuffers = track->GetReleasedBuffers(maxCount);
auto count = static_cast<u32>(releasedBuffers.size());
// Fill rest of output buffer with zeros
releasedBuffers.resize(maxCount, 0);
state.process->WriteMemory(releasedBuffers.data(), request.outputBuf.at(0).address, request.outputBuf.at(0).size);
response.Push<u32>(count);
}
void IAudioOut::ContainsAudioOutBuffer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto tag = request.Pop<u64>();
response.Push(static_cast<u32>(track->ContainsBuffer(tag)));
}
}