Skip to content

Commit f9060c6

Browse files
authored
RSDK-12151 Audio Out Component Type (#495)
1 parent db33762 commit f9060c6

File tree

15 files changed

+576
-0
lines changed

15 files changed

+576
-0
lines changed

codesamples/apis.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
"func": "get_properties",
1010
"args": []
1111
},
12+
"audio_out": {
13+
"client": "AudioOut",
14+
"func": "get_properties",
15+
"args": []
16+
},
1217
"button": {
1318
"client": "Button",
1419
"func": "push",

src/viam/sdk/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ endif()
6060

6161
target_sources(viamsdk
6262
PRIVATE
63+
common/audio.cpp
6364
common/audio.cpp
6465
common/client_helper.cpp
6566
common/exception.cpp
@@ -73,6 +74,7 @@ target_sources(viamsdk
7374
common/private/service_helper.cpp
7475
components/arm.cpp
7576
components/audio_in.cpp
77+
components/audio_out.cpp
7678
components/base.cpp
7779
components/board.cpp
7880
components/button.cpp
@@ -90,6 +92,8 @@ target_sources(viamsdk
9092
components/private/arm_server.cpp
9193
components/private/audio_in_server.cpp
9294
components/private/audio_in_client.cpp
95+
components/private/audio_out_client.cpp
96+
components/private/audio_out_server.cpp
9397
components/private/base_client.cpp
9498
components/private/base_server.cpp
9599
components/private/board_client.cpp
@@ -169,6 +173,7 @@ target_sources(viamsdk
169173
FILES
170174
../../viam/sdk/common/audio.hpp
171175
../../viam/sdk/common/client_helper.hpp
176+
../../viam/sdk/common/audio.hpp
172177
../../viam/sdk/common/exception.hpp
173178
../../viam/sdk/common/instance.hpp
174179
../../viam/sdk/common/linear_algebra.hpp
@@ -180,6 +185,7 @@ target_sources(viamsdk
180185
../../viam/sdk/common/world_state.hpp
181186
../../viam/sdk/components/arm.hpp
182187
../../viam/sdk/components/audio_in.hpp
188+
../../viam/sdk/components/audio_out.hpp
183189
../../viam/sdk/components/base.hpp
184190
../../viam/sdk/components/board.hpp
185191
../../viam/sdk/components/button.hpp

src/viam/sdk/common/audio.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ bool operator==(const audio_properties& lhs, const audio_properties& rhs) {
1919
std::tie(rhs.supported_codecs, rhs.sample_rate_hz, rhs.num_channels);
2020
}
2121

22+
bool operator==(const audio_info& lhs, const audio_info& rhs) {
23+
return std::tie(lhs.codec, lhs.sample_rate_hz, lhs.num_channels) ==
24+
std::tie(rhs.codec, rhs.sample_rate_hz, rhs.num_channels);
25+
}
26+
2227
uint16_t get_bits_per_sample(const std::string& codec) {
2328
if (codec == audio_codecs::PCM_16) {
2429
return 16;

src/viam/sdk/common/audio.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ struct audio_info {
3838
/// @brief Equality operator for properties
3939
bool operator==(const audio_properties& lhs, const audio_properties& rhs);
4040

41+
/// @brief Equality operator for audio_info
42+
bool operator==(const audio_info& lhs, const audio_info& rhs);
43+
4144
uint16_t get_bits_per_sample(const std::string& codec);
4245

4346
void write_wav_file(const std::string& filename,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#include <viam/sdk/components/audio_out.hpp>
2+
3+
#include <viam/sdk/common/audio.hpp>
4+
#include <viam/sdk/common/exception.hpp>
5+
#include <viam/sdk/common/utils.hpp>
6+
#include <viam/sdk/resource/resource.hpp>
7+
8+
namespace viam {
9+
namespace sdk {
10+
11+
API AudioOut::api() const {
12+
return API::get<AudioOut>();
13+
}
14+
15+
API API::traits<AudioOut>::api() {
16+
return {kRDK, kComponent, "audio_out"};
17+
}
18+
19+
AudioOut::AudioOut(std::string name) : Component(std::move(name)) {}
20+
21+
} // namespace sdk
22+
} // namespace viam
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/// @file components/audio_out.hpp
2+
///
3+
/// @brief Defines an `AudioOut` component.
4+
#pragma once
5+
6+
#include <string>
7+
8+
#include <boost/optional/optional.hpp>
9+
10+
#include <viam/sdk/common/audio.hpp>
11+
#include <viam/sdk/common/proto_value.hpp>
12+
#include <viam/sdk/common/utils.hpp>
13+
#include <viam/sdk/config/resource.hpp>
14+
15+
namespace viam {
16+
namespace sdk {
17+
18+
/// @defgroup AudioOut Classes related to the AudioOut component.
19+
20+
/// @class AudioOut audio_out.hpp "components/audio_out.hpp"
21+
/// @brief An `AudioOut` is a device that can output audio.
22+
/// @ingroup AudioOut
23+
///
24+
/// This acts as an abstract parent class to be inherited from by any drivers representing
25+
/// specific AudioOut implementations. This class cannot be used on its own.
26+
class AudioOut : public Component {
27+
public:
28+
using audio_info = viam::sdk::audio_info;
29+
30+
/// @brief Play audio data
31+
/// @param audio_data The audio data to play as bytes
32+
/// @param info Optional info about the audio_data (codec, sample rate, channels). Required for
33+
/// raw PCM data.
34+
inline void play(std::vector<uint8_t> const& audio_data, boost::optional<audio_info> info) {
35+
return play(audio_data, info, {});
36+
}
37+
38+
/// @brief Play audio through the audioout component
39+
/// @param audio_data The audio data to play
40+
/// @param info Optional info about the audio_data (codec, sample rate, channels). Required for
41+
/// raw PCM data.
42+
/// @param extra Any additional arguments to the method
43+
virtual void play(std::vector<uint8_t> const& audio_data,
44+
boost::optional<audio_info> info,
45+
const ProtoStruct& extra) = 0;
46+
47+
/// @brief Returns properties of the audio out device (supported codecs, sample rate, number of
48+
/// channels)
49+
inline audio_properties get_properties() {
50+
return get_properties({});
51+
}
52+
53+
/// @brief Returns properties of the audio out device (supported codecs, sample rate, number of
54+
/// channels)
55+
/// @param extra Any additional arguments to the method
56+
virtual audio_properties get_properties(const ProtoStruct& extra) = 0;
57+
58+
/// @brief Send/receive arbitrary commands to the resource.
59+
/// @param command the command to execute.
60+
/// @return The result of the executed command.
61+
virtual ProtoStruct do_command(const ProtoStruct& command) = 0;
62+
63+
// @brief Returns `GeometryConfig`s associated with the calling audioout.
64+
/// @return The requested `GeometryConfig`s associated with the component.
65+
inline std::vector<GeometryConfig> get_geometries() {
66+
return get_geometries({});
67+
}
68+
69+
/// @brief Returns `GeometryConfig`s associated with the calling audioout.
70+
/// @param extra Any additional arguments to the method.
71+
/// @return The requested `GeometryConfig`s associated with the component.
72+
virtual std::vector<GeometryConfig> get_geometries(const ProtoStruct& extra) = 0;
73+
74+
API api() const override;
75+
76+
protected:
77+
explicit AudioOut(std::string name);
78+
};
79+
80+
template <>
81+
struct API::traits<AudioOut> {
82+
static API api();
83+
};
84+
85+
} // namespace sdk
86+
} // namespace viam
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include <viam/sdk/components/private/audio_out_client.hpp>
2+
3+
#include <memory>
4+
#include <stdexcept>
5+
#include <string>
6+
#include <utility>
7+
8+
#include <viam/api/common/v1/common.pb.h>
9+
#include <viam/api/component/audioout/v1/audioout.grpc.pb.h>
10+
#include <viam/api/component/audioout/v1/audioout.pb.h>
11+
12+
#include <viam/sdk/common/client_helper.hpp>
13+
#include <viam/sdk/common/proto_value.hpp>
14+
#include <viam/sdk/common/utils.hpp>
15+
#include <viam/sdk/components/audio_out.hpp>
16+
#include <viam/sdk/config/resource.hpp>
17+
#include <viam/sdk/robot/client.hpp>
18+
19+
namespace viam {
20+
namespace sdk {
21+
namespace impl {
22+
23+
AudioOutClient::AudioOutClient(std::string name, std::shared_ptr<grpc::Channel> channel)
24+
: AudioOut(std::move(name)),
25+
stub_(viam::component::audioout::v1::AudioOutService::NewStub(channel)),
26+
channel_(std::move(channel)) {}
27+
28+
void AudioOutClient::play(std::vector<uint8_t> const& audio_data,
29+
boost::optional<audio_info> info,
30+
const ProtoStruct& extra) {
31+
return make_client_helper(this, *stub_, &StubType::Play)
32+
.with(extra,
33+
[&](auto& request) {
34+
// Convert audio_data from std::vector<uint8_t> to string
35+
std::string audio_data_str(audio_data.begin(), audio_data.end());
36+
request.set_audio_data(std::move(audio_data_str));
37+
38+
if (info) {
39+
::viam::common::v1::AudioInfo* proto_info = request.mutable_audio_info();
40+
proto_info->set_codec(info->codec);
41+
proto_info->set_sample_rate_hz(info->sample_rate_hz);
42+
proto_info->set_num_channels(info->num_channels);
43+
}
44+
})
45+
.invoke([](auto& response) {});
46+
}
47+
48+
audio_properties AudioOutClient::get_properties(const ProtoStruct& extra) {
49+
return make_client_helper(this, *stub_, &StubType::GetProperties)
50+
.with(extra)
51+
.invoke([](auto& response) {
52+
// Convert proto repeated field to vector
53+
std::vector<std::string> codecs;
54+
codecs.reserve(response.supported_codecs_size());
55+
for (const auto& codec : response.supported_codecs()) {
56+
codecs.push_back(codec);
57+
}
58+
59+
return audio_properties{
60+
std::move(codecs), response.sample_rate_hz(), response.num_channels()};
61+
});
62+
}
63+
64+
ProtoStruct AudioOutClient::do_command(const ProtoStruct& command) {
65+
return make_client_helper(this, *stub_, &StubType::DoCommand)
66+
.with([&](auto& request) { *request.mutable_command() = to_proto(command); })
67+
.invoke([](auto& response) { return from_proto(response.result()); });
68+
}
69+
70+
std::vector<GeometryConfig> AudioOutClient::get_geometries(const ProtoStruct& extra) {
71+
return make_client_helper(this, *stub_, &StubType::GetGeometries)
72+
.with(extra)
73+
.invoke([](auto& response) { return from_proto(response); });
74+
};
75+
76+
} // namespace impl
77+
} // namespace sdk
78+
} // namespace viam
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/// @file components/private/audio_out_client.hpp
2+
///
3+
/// @brief Implements a gRPC client for the `AudioOut` component
4+
#pragma once
5+
6+
#include <grpcpp/channel.h>
7+
8+
#include <viam/api/component/audioout/v1/audioout.grpc.pb.h>
9+
10+
#include <viam/sdk/components/audio_out.hpp>
11+
12+
namespace viam {
13+
namespace sdk {
14+
namespace impl {
15+
16+
/// @class AudioOutClient
17+
/// @brief gRPC client implementation of an `AudioOut` component.
18+
/// @ingroup AudioOut
19+
class AudioOutClient : public AudioOut {
20+
public:
21+
using interface_type = AudioOut;
22+
AudioOutClient(std::string name, std::shared_ptr<grpc::Channel> channel);
23+
24+
void play(std::vector<uint8_t> const& audio_data,
25+
boost::optional<audio_info> info,
26+
const ProtoStruct& extra) override;
27+
audio_properties get_properties(const ProtoStruct& extra) override;
28+
ProtoStruct do_command(const ProtoStruct& command) override;
29+
std::vector<GeometryConfig> get_geometries(const ProtoStruct& extra) override;
30+
31+
using AudioOut::get_geometries;
32+
using AudioOut::get_properties;
33+
using AudioOut::play;
34+
35+
private:
36+
using StubType = viam::component::audioout::v1::AudioOutService::StubInterface;
37+
std::unique_ptr<StubType> stub_;
38+
std::shared_ptr<grpc::Channel> channel_;
39+
};
40+
41+
} // namespace impl
42+
} // namespace sdk
43+
} // namespace viam
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include <viam/sdk/components/private/audio_out_server.hpp>
2+
3+
#include <viam/sdk/common/audio.hpp>
4+
#include <viam/sdk/common/private/service_helper.hpp>
5+
#include <viam/sdk/common/utils.hpp>
6+
#include <viam/sdk/spatialmath/geometry.hpp>
7+
8+
namespace viam {
9+
namespace sdk {
10+
namespace impl {
11+
12+
AudioOutServer::AudioOutServer(std::shared_ptr<ResourceManager> manager)
13+
: ResourceServer(std::move(manager)) {}
14+
15+
::grpc::Status AudioOutServer::Play(::grpc::ServerContext*,
16+
const ::viam::component::audioout::v1::PlayRequest* request,
17+
::viam::component::audioout::v1::PlayResponse*) noexcept {
18+
return make_service_helper<AudioOut>(
19+
"AudioOutServer::Play", this, request)([&](auto& helper, auto& audio_out) {
20+
// Convert audio_data from string to std::vector<uint8_t>
21+
std::vector<uint8_t> audio_data;
22+
const std::string& audio_data_str = request->audio_data();
23+
audio_data.assign(audio_data_str.c_str(), audio_data_str.c_str() + audio_data_str.size());
24+
25+
boost::optional<audio_info> info;
26+
if (request->has_audio_info()) {
27+
info.emplace(audio_info{request->audio_info().codec(),
28+
request->audio_info().sample_rate_hz(),
29+
request->audio_info().num_channels()});
30+
}
31+
audio_out->play(audio_data, info, helper.getExtra());
32+
});
33+
}
34+
35+
::grpc::Status AudioOutServer::DoCommand(::grpc::ServerContext*,
36+
const ::viam::common::v1::DoCommandRequest* request,
37+
::viam::common::v1::DoCommandResponse* response) noexcept {
38+
return make_service_helper<AudioOut>(
39+
"AudioOutServer::DoCommand", this, request)([&](auto&, auto& audio_out) {
40+
const ProtoStruct result = audio_out->do_command(from_proto(request->command()));
41+
*response->mutable_result() = to_proto(result);
42+
});
43+
}
44+
45+
::grpc::Status AudioOutServer::GetGeometries(
46+
::grpc::ServerContext*,
47+
const ::viam::common::v1::GetGeometriesRequest* request,
48+
::viam::common::v1::GetGeometriesResponse* response) noexcept {
49+
return make_service_helper<AudioOut>(
50+
"AudioOutServer::GetGeometries", this, request)([&](auto& helper, auto& audio_out) {
51+
const std::vector<GeometryConfig> geometries = audio_out->get_geometries(helper.getExtra());
52+
for (const auto& geometry : geometries) {
53+
*response->mutable_geometries()->Add() = to_proto(geometry);
54+
}
55+
});
56+
}
57+
58+
::grpc::Status AudioOutServer::GetProperties(
59+
::grpc::ServerContext*,
60+
const ::viam::common::v1::GetPropertiesRequest* request,
61+
::viam::common::v1::GetPropertiesResponse* response) noexcept {
62+
return make_service_helper<AudioOut>(
63+
"AudioOutServer::GetProperties", this, request)([&](auto& helper, auto& audio_out) {
64+
const audio_properties result = audio_out->get_properties(helper.getExtra());
65+
66+
// Copy supported_codecs vector to repeated field
67+
for (const auto& codec : result.supported_codecs) {
68+
response->add_supported_codecs(codec);
69+
}
70+
71+
response->set_sample_rate_hz(result.sample_rate_hz);
72+
response->set_num_channels(result.num_channels);
73+
});
74+
}
75+
76+
} // namespace impl
77+
} // namespace sdk
78+
} // namespace viam

0 commit comments

Comments
 (0)