2
Copyright (C) 2009 Red Hat, Inc.
4
This library is free software; you can redistribute it and/or
5
modify it under the terms of the GNU Lesser General Public
6
License as published by the Free Software Foundation; either
7
version 2.1 of the License, or (at your option) any later version.
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
Lesser General Public License for more details.
14
You should have received a copy of the GNU Lesser General Public
15
License along with this library; if not, see <http://www.gnu.org/licenses/>.
22
#include "red_client.h"
23
#include "audio_channels.h"
24
#include "audio_devices.h"
26
#define NUM_SAMPLES_MESSAGES 4
29
static uint32_t get_mm_time()
31
return uint32_t(Platform::get_monolithic_time() / (1000 * 1000));
34
class RecordSamplesMessage: public RedChannel::OutMessage {
36
RecordSamplesMessage(RecordChannel& channel);
37
virtual ~RecordSamplesMessage();
39
virtual RedPeer::OutMessage& peer_message() { return *_message;}
40
virtual void release();
43
RecordChannel& _channel;
44
RedPeer::OutMessage *_message;
47
RecordSamplesMessage::RecordSamplesMessage(RecordChannel& channel)
49
, _message (new Message(SPICE_MSGC_RECORD_DATA))
53
RecordSamplesMessage::~RecordSamplesMessage()
58
void RecordSamplesMessage::release()
60
_channel.release_message(this);
63
int RecordChannel::data_mode = SPICE_AUDIO_DATA_MODE_CELT_0_5_1;
65
class RecordHandler: public MessageHandlerImp<RecordChannel, SPICE_CHANNEL_RECORD> {
67
RecordHandler(RecordChannel& channel)
68
: MessageHandlerImp<RecordChannel, SPICE_CHANNEL_RECORD>(channel) {}
71
RecordChannel::RecordChannel(RedClient& client, uint32_t id)
72
: RedChannel(client, SPICE_CHANNEL_RECORD, id, new RecordHandler(*this))
73
, _wave_recorder (NULL)
74
, _mode (SPICE_AUDIO_DATA_MODE_INVALID)
76
, _celt_encoder (NULL)
78
for (int i = 0; i < NUM_SAMPLES_MESSAGES; i++) {
79
_messages.push_front(new RecordSamplesMessage(*this));
82
RecordHandler* handler = static_cast<RecordHandler*>(get_message_handler());
84
handler->set_handler(SPICE_MSG_MIGRATE, &RecordChannel::handle_migrate);
85
handler->set_handler(SPICE_MSG_SET_ACK, &RecordChannel::handle_set_ack);
86
handler->set_handler(SPICE_MSG_PING, &RecordChannel::handle_ping);
87
handler->set_handler(SPICE_MSG_WAIT_FOR_CHANNELS, &RecordChannel::handle_wait_for_channels);
88
handler->set_handler(SPICE_MSG_DISCONNECTING, &RecordChannel::handle_disconnect);
89
handler->set_handler(SPICE_MSG_NOTIFY, &RecordChannel::handle_notify);
91
handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start);
93
set_capability(SPICE_RECORD_CAP_CELT_0_5_1);
96
RecordChannel::~RecordChannel(void)
98
while (!_messages.empty()) {
99
RecordSamplesMessage *mes;
100
mes = *_messages.begin();
101
_messages.pop_front();
107
bool RecordChannel::abort(void)
109
return (!_wave_recorder || _wave_recorder->abort()) && RedChannel::abort();
112
void RecordChannel::on_connect()
114
Message* message = new Message(SPICE_MSGC_RECORD_MODE);
115
SpiceMsgcRecordMode mode;
116
mode.time = get_mm_time();
118
test_capability(SPICE_RECORD_CAP_CELT_0_5_1) ? RecordChannel::data_mode :
119
SPICE_AUDIO_DATA_MODE_RAW;
120
_marshallers->msgc_record_mode(message->marshaller(), &mode);
121
post_message(message);
124
void RecordChannel::on_disconnect()
129
void RecordChannel::send_start_mark()
131
Message* message = new Message(SPICE_MSGC_RECORD_START_MARK);
132
SpiceMsgcRecordStartMark start_mark;
133
start_mark.time = get_mm_time();
134
_marshallers->msgc_record_start_mark(message->marshaller(), &start_mark);
135
post_message(message);
138
void RecordChannel::handle_start(RedPeer::InMessage* message)
140
RecordHandler* handler = static_cast<RecordHandler*>(get_message_handler());
141
SpiceMsgRecordStart* start = (SpiceMsgRecordStart*)message->data();
143
handler->set_handler(SPICE_MSG_RECORD_START, NULL);
144
handler->set_handler(SPICE_MSG_RECORD_STOP, &RecordChannel::handle_stop);
145
ASSERT(!_wave_recorder && !_celt_mode && !_celt_encoder);
147
// for now support only one setting
148
if (start->format != SPICE_AUDIO_FMT_S16) {
149
THROW("unexpected format");
152
int bits_per_sample = 16;
154
_wave_recorder = Platform::create_recorder(*this, start->frequency,
158
LOG_WARN("create recorder failed");
162
int frame_size = 256;
164
_frame_bytes = frame_size * bits_per_sample * start->channels / 8;
165
if (!(_celt_mode = celt051_mode_create(start->frequency, start->channels, frame_size,
167
THROW("create celt mode failed %d", celt_mode_err);
170
if (!(_celt_encoder = celt051_encoder_create(_celt_mode))) {
171
THROW("create celt encoder failed");
175
_wave_recorder->start();
178
void RecordChannel::clear()
180
if (_wave_recorder) {
181
_wave_recorder->stop();
182
delete _wave_recorder;
183
_wave_recorder = NULL;
186
celt051_encoder_destroy(_celt_encoder);
187
_celt_encoder = NULL;
190
celt051_mode_destroy(_celt_mode);
195
void RecordChannel::handle_stop(RedPeer::InMessage* message)
197
RecordHandler* handler = static_cast<RecordHandler*>(get_message_handler());
198
handler->set_handler(SPICE_MSG_RECORD_START, &RecordChannel::handle_start);
199
handler->set_handler(SPICE_MSG_RECORD_STOP, NULL);
200
if (!_wave_recorder) {
203
ASSERT(_celt_mode && _celt_encoder);
207
RecordSamplesMessage* RecordChannel::get_message()
209
Lock lock(_messages_lock);
210
if (_messages.empty()) {
214
RecordSamplesMessage* ret = *_messages.begin();
215
_messages.pop_front();
219
void RecordChannel::release_message(RecordSamplesMessage *message)
221
Lock lock(_messages_lock);
222
_messages.push_front(message);
225
void RecordChannel::add_event_source(EventSources::File& event_source)
227
get_process_loop().add_file(event_source);
230
void RecordChannel::remove_event_source(EventSources::File& event_source)
232
get_process_loop().remove_file(event_source);
235
void RecordChannel::add_event_source(EventSources::Trigger& event_source)
237
get_process_loop().add_trigger(event_source);
240
void RecordChannel::remove_event_source(EventSources::Trigger& event_source)
242
get_process_loop().remove_trigger(event_source);
245
#define FRAME_SIZE 256
246
#define CELT_BIT_RATE (64 * 1024)
247
#define CELT_COMPRESSED_FRAME_BYTES (FRAME_SIZE * CELT_BIT_RATE / 44100 / 8)
249
void RecordChannel::push_frame(uint8_t *frame)
251
RecordSamplesMessage *message;
252
ASSERT(_frame_bytes == FRAME_SIZE * 4);
253
if (!(message = get_message())) {
257
uint8_t celt_buf[CELT_COMPRESSED_FRAME_BYTES];
260
if (_mode == SPICE_AUDIO_DATA_MODE_CELT_0_5_1) {
261
n = celt051_encode(_celt_encoder, (celt_int16_t *)frame, NULL, celt_buf,
262
CELT_COMPRESSED_FRAME_BYTES);
264
THROW("celt encode failed");
270
RedPeer::OutMessage& peer_message = message->peer_message();
271
peer_message.reset(SPICE_MSGC_RECORD_DATA);
272
SpiceMsgcRecordPacket packet;
273
packet.time = get_mm_time();
274
_marshallers->msgc_record_data(peer_message.marshaller(), &packet);
275
spice_marshaller_add(peer_message.marshaller(), frame, n);
276
post_message(message);
279
class RecordFactory: public ChannelFactory {
281
RecordFactory() : ChannelFactory(SPICE_CHANNEL_RECORD) {}
282
virtual RedChannel* construct(RedClient& client, uint32_t id)
284
return new RecordChannel(client, id);
288
static RecordFactory factory;
290
ChannelFactory& RecordChannel::Factory()