summaryrefslogblamecommitdiffstats
path: root/src/core/hle/service/audio/audio_device.cpp
blob: 3608d08c789dd569ee26a6218e756443f8146a12 (plain) (tree)






















































































































































































                                                                                            
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "audio_core/audio_core.h"
#include "common/string_util.h"
#include "core/hle/service/audio/audio_device.h"
#include "core/hle/service/ipc_helpers.h"

namespace Service::Audio {
using namespace AudioCore::Renderer;

IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u32 revision,
                           u32 device_num)
    : ServiceFramework{system_, "IAudioDevice"}, service_context{system_, "IAudioDevice"},
      impl{std::make_unique<AudioDevice>(system_, applet_resource_user_id, revision)},
      event{service_context.CreateEvent(fmt::format("IAudioDeviceEvent-{}", device_num))} {
    static const FunctionInfo functions[] = {
        {0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
        {1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
        {2, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolume"},
        {3, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceName"},
        {4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
        {5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
        {6, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceNameAuto"},
        {7, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolumeAuto"},
        {8, &IAudioDevice::GetAudioDeviceOutputVolume, "GetAudioDeviceOutputVolumeAuto"},
        {10, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioDeviceNameAuto"},
        {11, &IAudioDevice::QueryAudioDeviceInputEvent, "QueryAudioDeviceInputEvent"},
        {12, &IAudioDevice::QueryAudioDeviceOutputEvent, "QueryAudioDeviceOutputEvent"},
        {13, &IAudioDevice::GetActiveAudioDeviceName, "GetActiveAudioOutputDeviceName"},
        {14, &IAudioDevice::ListAudioOutputDeviceName, "ListAudioOutputDeviceName"},
    };
    RegisterHandlers(functions);

    event->Signal();
}

IAudioDevice::~IAudioDevice() {
    service_context.CloseEvent(event);
}

void IAudioDevice::ListAudioDeviceName(HLERequestContext& ctx) {
    const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();

    std::vector<AudioDevice::AudioDeviceName> out_names{};

    const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);

    std::string out{};
    for (u32 i = 0; i < out_count; i++) {
        std::string a{};
        u32 j = 0;
        while (out_names[i].name[j] != '\0') {
            a += out_names[i].name[j];
            j++;
        }
        out += "\n\t" + a;
    }

    LOG_DEBUG(Service_Audio, "called.\nNames={}", out);

    IPC::ResponseBuilder rb{ctx, 3};

    ctx.WriteBuffer(out_names);

    rb.Push(ResultSuccess);
    rb.Push(out_count);
}

void IAudioDevice::SetAudioDeviceOutputVolume(HLERequestContext& ctx) {
    IPC::RequestParser rp{ctx};
    const f32 volume = rp.Pop<f32>();

    const auto device_name_buffer = ctx.ReadBuffer();
    const std::string name = Common::StringFromBuffer(device_name_buffer);

    LOG_DEBUG(Service_Audio, "called. name={}, volume={}", name, volume);

    if (name == "AudioTvOutput") {
        impl->SetDeviceVolumes(volume);
    }

    IPC::ResponseBuilder rb{ctx, 2};
    rb.Push(ResultSuccess);
}

void IAudioDevice::GetAudioDeviceOutputVolume(HLERequestContext& ctx) {
    const auto device_name_buffer = ctx.ReadBuffer();
    const std::string name = Common::StringFromBuffer(device_name_buffer);

    LOG_DEBUG(Service_Audio, "called. Name={}", name);

    f32 volume{1.0f};
    if (name == "AudioTvOutput") {
        volume = impl->GetDeviceVolume(name);
    }

    IPC::ResponseBuilder rb{ctx, 3};
    rb.Push(ResultSuccess);
    rb.Push(volume);
}

void IAudioDevice::GetActiveAudioDeviceName(HLERequestContext& ctx) {
    const auto write_size = ctx.GetWriteBufferSize();
    std::string out_name{"AudioTvOutput"};

    LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name);

    out_name.resize(write_size);

    ctx.WriteBuffer(out_name);

    IPC::ResponseBuilder rb{ctx, 2};
    rb.Push(ResultSuccess);
}

void IAudioDevice::QueryAudioDeviceSystemEvent(HLERequestContext& ctx) {
    LOG_DEBUG(Service_Audio, "(STUBBED) called");

    event->Signal();

    IPC::ResponseBuilder rb{ctx, 2, 1};
    rb.Push(ResultSuccess);
    rb.PushCopyObjects(event->GetReadableEvent());
}

void IAudioDevice::GetActiveChannelCount(HLERequestContext& ctx) {
    const auto& sink{system.AudioCore().GetOutputSink()};
    u32 channel_count{sink.GetSystemChannels()};

    LOG_DEBUG(Service_Audio, "(STUBBED) called. Channels={}", channel_count);

    IPC::ResponseBuilder rb{ctx, 3};

    rb.Push(ResultSuccess);
    rb.Push<u32>(channel_count);
}

void IAudioDevice::QueryAudioDeviceInputEvent(HLERequestContext& ctx) {
    LOG_DEBUG(Service_Audio, "(STUBBED) called");

    IPC::ResponseBuilder rb{ctx, 2, 1};
    rb.Push(ResultSuccess);
    rb.PushCopyObjects(event->GetReadableEvent());
}

void IAudioDevice::QueryAudioDeviceOutputEvent(HLERequestContext& ctx) {
    LOG_DEBUG(Service_Audio, "called");

    IPC::ResponseBuilder rb{ctx, 2, 1};
    rb.Push(ResultSuccess);
    rb.PushCopyObjects(event->GetReadableEvent());
}

void IAudioDevice::ListAudioOutputDeviceName(HLERequestContext& ctx) {
    const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>();

    std::vector<AudioDevice::AudioDeviceName> out_names{};

    const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);

    std::string out{};
    for (u32 i = 0; i < out_count; i++) {
        std::string a{};
        u32 j = 0;
        while (out_names[i].name[j] != '\0') {
            a += out_names[i].name[j];
            j++;
        }
        out += "\n\t" + a;
    }

    LOG_DEBUG(Service_Audio, "called.\nNames={}", out);

    IPC::ResponseBuilder rb{ctx, 3};

    ctx.WriteBuffer(out_names);

    rb.Push(ResultSuccess);
    rb.Push(out_count);
}

} // namespace Service::Audio