-
-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathDriver.cpp
More file actions
146 lines (117 loc) · 4.41 KB
/
Driver.cpp
File metadata and controls
146 lines (117 loc) · 4.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright (c) libASPL authors
// Licensed under MIT
#include <aspl/Driver.hpp>
#include <CoreAudio/AudioServerPlugIn.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
namespace {
// Destination UDP address.
constexpr const char* SocketAddr = "127.0.0.1";
constexpr short SocketPort = 4444;
constexpr UInt32 SocketPacketSize = 512;
// Stream format.
constexpr UInt32 SampleRate = 44100;
constexpr UInt32 ChannelCount = 2;
// Control and I/O request handler.
class ExampleHandler : public aspl::ControlRequestHandler, public aspl::IORequestHandler
{
public:
// Invoked on control thread before first I/O request.
OSStatus OnStartIO() override
{
socket_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (socket_ == -1) {
return kAudioHardwareUnspecifiedError;
}
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(SocketPort);
inet_pton(AF_INET, SocketAddr, &addr.sin_addr);
if (connect(socket_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
close(socket_);
socket_ = -1;
return kAudioHardwareUnspecifiedError;
}
return kAudioHardwareNoError;
}
// Invoked on control thread after last I/O request.
void OnStopIO() override
{
if (socket_ != -1) {
close(socket_);
socket_ = -1;
}
}
// Invoked on realtime I/O thread to write mixed data from clients.
void OnWriteMixedOutput(const std::shared_ptr<aspl::Stream>& stream,
Float64 zeroTimestamp,
Float64 timestamp,
const void* buff,
UInt32 buffBytesSize) override
{
while (buffBytesSize != 0) {
const UInt32 packetBytesSize = std::min(buffBytesSize, SocketPacketSize);
send(socket_, buff, packetBytesSize, MSG_DONTWAIT);
buff = reinterpret_cast<const UInt8*>(buff) + packetBytesSize;
buffBytesSize -= packetBytesSize;
}
}
private:
int socket_ = -1;
};
std::shared_ptr<aspl::Driver> CreateExampleDriver()
{
// Create context, shared between all other objects.
// You can provide custom tracer here.
auto context = std::make_shared<aspl::Context>();
// Create device object with some custom parameters.
aspl::DeviceParameters deviceParams;
deviceParams.Name = "Netcat Device (libASPL)";
deviceParams.SampleRate = SampleRate;
deviceParams.ChannelCount = ChannelCount;
deviceParams.EnableMixing = true;
auto device = std::make_shared<aspl::Device>(context, deviceParams);
// Add to device one stream, one volume control, and one mute control.
// Associate volume and mute control with the stream.
//
// If desired, you can provide parameters for streams and controls as well,
// but for simplicity we use defaults here.
//
// HAL will use stream and controls to determine how to work with our device
// and to store volume and mute settings.
//
// IORequestHandler will use stream to apply stored volume and mute settings.
device->AddStreamWithControlsAsync(aspl::Direction::Output);
// Create and set custom handler for both control and I/O requests.
// You can use separate handlers, but here we use one.
auto handler = std::make_shared<ExampleHandler>();
device->SetControlHandler(handler);
device->SetIOHandler(handler);
// Create plugin object, the root of the object hierarchy, and add
// our device to it.
//
// The main purpose of plugin is to provide the list of devices to HAL.
//
// For simplicity we use default parameters.
auto plugin = std::make_shared<aspl::Plugin>(context);
plugin->AddDevice(device);
// Create driver, the top-level entry point.
// Driver owns plugin object and thus the whole object hierarchy,
// and provides C interface for HAL.
auto driver = std::make_shared<aspl::Driver>(context, plugin);
return driver;
}
} // namespace
extern "C" void* ExampleEntryPoint(CFAllocatorRef allocator, CFUUIDRef typeUUID)
{
// The UUID of the plug-in type (443ABAB8-E7B3-491A-B985-BEB9187030DB).
if (!CFEqual(typeUUID, kAudioServerPlugInTypeUUID)) {
return nullptr;
}
// Store shared pointer to the driver to keep it alive.
static std::shared_ptr<aspl::Driver> driver = CreateExampleDriver();
return driver->GetReference();
}