Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions codesamples/apis.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
"func": "get_properties",
"args": []
},
"audio_out": {
"client": "AudioOut",
"func": "get_properties",
"args": []
},
"button": {
"client": "Button",
"func": "push",
Expand Down
6 changes: 6 additions & 0 deletions src/viam/sdk/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ endif()

target_sources(viamsdk
PRIVATE
common/audio.cpp
common/audio.cpp
common/client_helper.cpp
common/exception.cpp
Expand All @@ -73,6 +74,7 @@ target_sources(viamsdk
common/private/service_helper.cpp
components/arm.cpp
components/audio_in.cpp
components/audio_out.cpp
components/base.cpp
components/board.cpp
components/button.cpp
Expand All @@ -90,6 +92,8 @@ target_sources(viamsdk
components/private/arm_server.cpp
components/private/audio_in_server.cpp
components/private/audio_in_client.cpp
components/private/audio_out_client.cpp
components/private/audio_out_server.cpp
components/private/base_client.cpp
components/private/base_server.cpp
components/private/board_client.cpp
Expand Down Expand Up @@ -169,6 +173,7 @@ target_sources(viamsdk
FILES
../../viam/sdk/common/audio.hpp
../../viam/sdk/common/client_helper.hpp
../../viam/sdk/common/audio.hpp
../../viam/sdk/common/exception.hpp
../../viam/sdk/common/instance.hpp
../../viam/sdk/common/linear_algebra.hpp
Expand All @@ -180,6 +185,7 @@ target_sources(viamsdk
../../viam/sdk/common/world_state.hpp
../../viam/sdk/components/arm.hpp
../../viam/sdk/components/audio_in.hpp
../../viam/sdk/components/audio_out.hpp
../../viam/sdk/components/base.hpp
../../viam/sdk/components/board.hpp
../../viam/sdk/components/button.hpp
Expand Down
5 changes: 5 additions & 0 deletions src/viam/sdk/common/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ bool operator==(const audio_properties& lhs, const audio_properties& rhs) {
std::tie(rhs.supported_codecs, rhs.sample_rate_hz, rhs.num_channels);
}

bool operator==(const audio_info& lhs, const audio_info& rhs) {
return std::tie(lhs.codec, lhs.sample_rate_hz, lhs.num_channels) ==
std::tie(rhs.codec, rhs.sample_rate_hz, rhs.num_channels);
}

uint16_t get_bits_per_sample(const std::string& codec) {
if (codec == audio_codecs::PCM_16) {
return 16;
Expand Down
3 changes: 3 additions & 0 deletions src/viam/sdk/common/audio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ struct audio_info {
/// @brief Equality operator for properties
bool operator==(const audio_properties& lhs, const audio_properties& rhs);

/// @brief Equality operator for audio_info
bool operator==(const audio_info& lhs, const audio_info& rhs);

uint16_t get_bits_per_sample(const std::string& codec);

void write_wav_file(const std::string& filename,
Expand Down
22 changes: 22 additions & 0 deletions src/viam/sdk/components/audio_out.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include <viam/sdk/components/audio_out.hpp>

#include <viam/sdk/common/audio.hpp>
#include <viam/sdk/common/exception.hpp>
#include <viam/sdk/common/utils.hpp>
#include <viam/sdk/resource/resource.hpp>

namespace viam {
namespace sdk {

API AudioOut::api() const {
return API::get<AudioOut>();
}

API API::traits<AudioOut>::api() {
return {kRDK, kComponent, "audio_out"};
}

AudioOut::AudioOut(std::string name) : Component(std::move(name)) {}

} // namespace sdk
} // namespace viam
86 changes: 86 additions & 0 deletions src/viam/sdk/components/audio_out.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/// @file components/audio_out.hpp
///
/// @brief Defines an `AudioOut` component.
#pragma once

#include <string>

#include <boost/optional/optional.hpp>

#include <viam/sdk/common/audio.hpp>
#include <viam/sdk/common/proto_value.hpp>
#include <viam/sdk/common/utils.hpp>
#include <viam/sdk/config/resource.hpp>

namespace viam {
namespace sdk {

/// @defgroup AudioOut Classes related to the AudioOut component.

/// @class AudioOut audio_out.hpp "components/audio_out.hpp"
/// @brief An `AudioOut` is a device that can output audio.
/// @ingroup AudioOut
///
/// This acts as an abstract parent class to be inherited from by any drivers representing
/// specific AudioOut implementations. This class cannot be used on its own.
class AudioOut : public Component {
public:
using audio_info = viam::sdk::audio_info;

/// @brief Play audio data
/// @param audio_data The audio data to play as bytes
/// @param info Optional info about the audio_data (codec, sample rate, channels). Required for
/// raw PCM data.
inline void play(std::vector<uint8_t> const& audio_data, boost::optional<audio_info> info) {
return play(audio_data, info, {});
}

/// @brief Play audio through the audioout component
/// @param audio_data The audio data to play
/// @param info Optional info about the audio_data (codec, sample rate, channels). Required for
/// raw PCM data.
/// @param extra Any additional arguments to the method
virtual void play(std::vector<uint8_t> const& audio_data,
boost::optional<audio_info> info,
const ProtoStruct& extra) = 0;

/// @brief Returns properties of the audio out device (supported codecs, sample rate, number of
/// channels)
inline audio_properties get_properties() {
return get_properties({});
}

/// @brief Returns properties of the audio out device (supported codecs, sample rate, number of
/// channels)
/// @param extra Any additional arguments to the method
virtual audio_properties get_properties(const ProtoStruct& extra) = 0;

/// @brief Send/receive arbitrary commands to the resource.
/// @param command the command to execute.
/// @return The result of the executed command.
virtual ProtoStruct do_command(const ProtoStruct& command) = 0;

// @brief Returns `GeometryConfig`s associated with the calling audioout.
/// @return The requested `GeometryConfig`s associated with the component.
inline std::vector<GeometryConfig> get_geometries() {
return get_geometries({});
}

/// @brief Returns `GeometryConfig`s associated with the calling audioout.
/// @param extra Any additional arguments to the method.
/// @return The requested `GeometryConfig`s associated with the component.
virtual std::vector<GeometryConfig> get_geometries(const ProtoStruct& extra) = 0;

API api() const override;

protected:
explicit AudioOut(std::string name);
};

template <>
struct API::traits<AudioOut> {
static API api();
};

} // namespace sdk
} // namespace viam
78 changes: 78 additions & 0 deletions src/viam/sdk/components/private/audio_out_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <viam/sdk/components/private/audio_out_client.hpp>

#include <memory>
#include <stdexcept>
#include <string>
#include <utility>

#include <viam/api/common/v1/common.pb.h>
#include <viam/api/component/audioout/v1/audioout.grpc.pb.h>
#include <viam/api/component/audioout/v1/audioout.pb.h>

#include <viam/sdk/common/client_helper.hpp>
#include <viam/sdk/common/proto_value.hpp>
#include <viam/sdk/common/utils.hpp>
#include <viam/sdk/components/audio_out.hpp>
#include <viam/sdk/config/resource.hpp>
#include <viam/sdk/robot/client.hpp>

namespace viam {
namespace sdk {
namespace impl {

AudioOutClient::AudioOutClient(std::string name, std::shared_ptr<grpc::Channel> channel)
: AudioOut(std::move(name)),
stub_(viam::component::audioout::v1::AudioOutService::NewStub(channel)),
channel_(std::move(channel)) {}

void AudioOutClient::play(std::vector<uint8_t> const& audio_data,
boost::optional<audio_info> info,
const ProtoStruct& extra) {
return make_client_helper(this, *stub_, &StubType::Play)
.with(extra,
[&](auto& request) {
// Convert audio_data from std::vector<uint8_t> to string
std::string audio_data_str(audio_data.begin(), audio_data.end());
request.set_audio_data(std::move(audio_data_str));

if (info) {
::viam::common::v1::AudioInfo* proto_info = request.mutable_audio_info();
proto_info->set_codec(info->codec);
proto_info->set_sample_rate_hz(info->sample_rate_hz);
proto_info->set_num_channels(info->num_channels);
}
})
.invoke([](auto& response) {});
}

audio_properties AudioOutClient::get_properties(const ProtoStruct& extra) {
return make_client_helper(this, *stub_, &StubType::GetProperties)
.with(extra)
.invoke([](auto& response) {
// Convert proto repeated field to vector
std::vector<std::string> codecs;
codecs.reserve(response.supported_codecs_size());
for (const auto& codec : response.supported_codecs()) {
codecs.push_back(codec);
}

return audio_properties{
std::move(codecs), response.sample_rate_hz(), response.num_channels()};
});
}

ProtoStruct AudioOutClient::do_command(const ProtoStruct& command) {
return make_client_helper(this, *stub_, &StubType::DoCommand)
.with([&](auto& request) { *request.mutable_command() = to_proto(command); })
.invoke([](auto& response) { return from_proto(response.result()); });
}

std::vector<GeometryConfig> AudioOutClient::get_geometries(const ProtoStruct& extra) {
return make_client_helper(this, *stub_, &StubType::GetGeometries)
.with(extra)
.invoke([](auto& response) { return from_proto(response); });
};

} // namespace impl
} // namespace sdk
} // namespace viam
43 changes: 43 additions & 0 deletions src/viam/sdk/components/private/audio_out_client.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/// @file components/private/audio_out_client.hpp
///
/// @brief Implements a gRPC client for the `AudioOut` component
#pragma once

#include <grpcpp/channel.h>

#include <viam/api/component/audioout/v1/audioout.grpc.pb.h>

#include <viam/sdk/components/audio_out.hpp>

namespace viam {
namespace sdk {
namespace impl {

/// @class AudioOutClient
/// @brief gRPC client implementation of an `AudioOut` component.
/// @ingroup AudioOut
class AudioOutClient : public AudioOut {
public:
using interface_type = AudioOut;
AudioOutClient(std::string name, std::shared_ptr<grpc::Channel> channel);

void play(std::vector<uint8_t> const& audio_data,
boost::optional<audio_info> info,
const ProtoStruct& extra) override;
audio_properties get_properties(const ProtoStruct& extra) override;
ProtoStruct do_command(const ProtoStruct& command) override;
std::vector<GeometryConfig> get_geometries(const ProtoStruct& extra) override;

using AudioOut::get_geometries;
using AudioOut::get_properties;
using AudioOut::play;

private:
using StubType = viam::component::audioout::v1::AudioOutService::StubInterface;
std::unique_ptr<StubType> stub_;
std::shared_ptr<grpc::Channel> channel_;
};

} // namespace impl
} // namespace sdk
} // namespace viam
78 changes: 78 additions & 0 deletions src/viam/sdk/components/private/audio_out_server.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include <viam/sdk/components/private/audio_out_server.hpp>

#include <viam/sdk/common/audio.hpp>
#include <viam/sdk/common/private/service_helper.hpp>
#include <viam/sdk/common/utils.hpp>
#include <viam/sdk/spatialmath/geometry.hpp>

namespace viam {
namespace sdk {
namespace impl {

AudioOutServer::AudioOutServer(std::shared_ptr<ResourceManager> manager)
: ResourceServer(std::move(manager)) {}

::grpc::Status AudioOutServer::Play(::grpc::ServerContext*,
const ::viam::component::audioout::v1::PlayRequest* request,
::viam::component::audioout::v1::PlayResponse*) noexcept {
return make_service_helper<AudioOut>(
"AudioOutServer::Play", this, request)([&](auto& helper, auto& audio_out) {
// Convert audio_data from string to std::vector<uint8_t>
std::vector<uint8_t> audio_data;
const std::string& audio_data_str = request->audio_data();
audio_data.assign(audio_data_str.c_str(), audio_data_str.c_str() + audio_data_str.size());

boost::optional<audio_info> info;
if (request->has_audio_info()) {
info.emplace(audio_info{request->audio_info().codec(),
request->audio_info().sample_rate_hz(),
request->audio_info().num_channels()});
}
audio_out->play(audio_data, info, helper.getExtra());
});
}

::grpc::Status AudioOutServer::DoCommand(::grpc::ServerContext*,
const ::viam::common::v1::DoCommandRequest* request,
::viam::common::v1::DoCommandResponse* response) noexcept {
return make_service_helper<AudioOut>(
"AudioOutServer::DoCommand", this, request)([&](auto&, auto& audio_out) {
const ProtoStruct result = audio_out->do_command(from_proto(request->command()));
*response->mutable_result() = to_proto(result);
});
}

::grpc::Status AudioOutServer::GetGeometries(
::grpc::ServerContext*,
const ::viam::common::v1::GetGeometriesRequest* request,
::viam::common::v1::GetGeometriesResponse* response) noexcept {
return make_service_helper<AudioOut>(
"AudioOutServer::GetGeometries", this, request)([&](auto& helper, auto& audio_out) {
const std::vector<GeometryConfig> geometries = audio_out->get_geometries(helper.getExtra());
for (const auto& geometry : geometries) {
*response->mutable_geometries()->Add() = to_proto(geometry);
}
});
}

::grpc::Status AudioOutServer::GetProperties(
::grpc::ServerContext*,
const ::viam::common::v1::GetPropertiesRequest* request,
::viam::common::v1::GetPropertiesResponse* response) noexcept {
return make_service_helper<AudioOut>(
"AudioOutServer::GetProperties", this, request)([&](auto& helper, auto& audio_out) {
const audio_properties result = audio_out->get_properties(helper.getExtra());

// Copy supported_codecs vector to repeated field
for (const auto& codec : result.supported_codecs) {
response->add_supported_codecs(codec);
}

response->set_sample_rate_hz(result.sample_rate_hz);
response->set_num_channels(result.num_channels);
});
}

} // namespace impl
} // namespace sdk
} // namespace viam
Loading