20 #include "audio_converter.h"
24 #define SOCKET_PATH "/tmp/acm-songid"
26 using namespace audiocapturemgr;
27 const unsigned int DEFAULT_PRECAPTURE_DURATION_SEC = 6;
28 static unsigned int ticker = 0;
29 static void connected_callback(
void * data)
35 music_id_client::music_id_client(
q_mgr * manager, preferred_delivery_method_t mode) :
audio_capture_client(manager), m_worker_thread_alive(true), m_total_size(0),
36 m_queue_upper_limit_bytes(0), m_request_counter(0), m_enable_wav_header_output(false), m_convert_output(false), m_delivery_method(mode), m_sock_path(SOCKET_PATH + get_suffix(ticker++))
38 DEBUG(
"Creating instance.\n");
39 set_precapture_duration(DEFAULT_PRECAPTURE_DURATION_SEC);
43 if(SOCKET_OUTPUT == m_delivery_method)
45 INFO(
"Socket delivery selected for audio clip.\n");
46 m_sock_adaptor =
nullptr;
48 m_sock_adaptor->start_listening(m_sock_path);
49 m_sock_adaptor->register_data_ready_callback(connected_callback,
this);
53 music_id_client::~music_id_client()
55 DEBUG(
"Deleting instance.\n");
56 m_worker_thread_alive =
false;
57 if(m_worker_thread.joinable())
59 m_worker_thread.join();
63 INFO(
"Flushing request queue. Size is %d\n", m_requests.size());
64 std::list<request_t *>::iterator req_iter;
65 for(req_iter = m_requests.begin(); req_iter != m_requests.end(); req_iter++)
71 INFO(
"Flushing buffers.\n");
72 std::list<audio_buffer *>::iterator buf_iter;
73 for(buf_iter = m_queue.begin(); buf_iter != m_queue.end(); buf_iter++)
75 release_buffer(*buf_iter);
79 if(SOCKET_OUTPUT == m_delivery_method)
81 delete m_sock_adaptor;
82 INFO(
"Outbox has %d entries. Flushing.\n", m_outbox.size());
83 for(
auto & outbox_entry : m_outbox)
94 m_queue.push_back(buf);
95 m_total_size += buf->m_size;
103 m_precapture_duration_seconds = seconds;
104 m_precapture_size_bytes = seconds * m_manager->
get_data_rate();
105 if(m_queue_upper_limit_bytes < m_precapture_size_bytes)
107 m_queue_upper_limit_bytes = m_precapture_size_bytes;
109 compute_queue_size();
118 ret = audio_capture_client::set_audio_properties(properties);
122 m_precapture_size_bytes = m_precapture_duration_seconds * m_manager->
get_data_rate();
129 audio_capture_client::get_audio_properties(properties);
132 properties.format = m_output_properties.format;
133 properties.sampling_frequency = m_output_properties.sampling_frequency;
137 void music_id_client::trim_queue()
139 int excess_bytes = m_total_size - m_queue_upper_limit_bytes;
140 DEBUG(
"excess_bytes = %d\n", excess_bytes);
141 while(0 < excess_bytes)
144 unsigned int current_buffer_size = m_queue.front()->m_size;
145 if((
unsigned int)excess_bytes >= current_buffer_size)
147 excess_bytes -= current_buffer_size;
148 m_total_size -= current_buffer_size;
149 release_buffer((m_queue.front()));
164 if(0 != m_outbox.size())
166 sink_ptr = m_outbox.front();
167 m_outbox.pop_front();
173 INFO(
"Sending clip.\n");
174 m_sock_adaptor->
write_data(sink_ptr->get_buffer(), sink_ptr->get_size());
176 INFO(
"Done sending.\n");
180 WARN(
"No data in outbox.\n");
189 if(SOCKET_OUTPUT == m_delivery_method)
191 ret = grab_last_n_seconds(m_precapture_duration_seconds);
195 ret = grab_last_n_seconds(filename, m_precapture_duration_seconds);
201 int music_id_client::grab_last_n_seconds(
unsigned int seconds)
207 if(0 != m_queue.size())
210 audio_capture_client::get_audio_properties(in_properties);
216 converter.convert(m_queue, data_dump_size);
222 converter.convert(m_queue, data_dump_size);
224 m_outbox.push_back(sink);
225 INFO(
"Precaptured sample placed in outbox.\n");
229 ERROR(
"Error! Precaptured queue is empty.\n");
235 int music_id_client::grab_last_n_seconds(
const std::string &filename,
unsigned int seconds)
240 if(0 != m_queue.size())
242 std::ofstream file(filename.c_str(), std::ios::binary);
245 if(m_enable_wav_header_output)
247 write_default_file_header(file);
251 audio_capture_client::get_audio_properties(in_properties);
256 converter.convert(m_queue, data_dump_size);
261 converter.convert(m_queue, data_dump_size);
264 if(m_enable_wav_header_output)
266 unsigned int payload_size =
static_cast<unsigned int>(file.tellp()) - 44;
267 update_file_header_size(file, payload_size);
269 INFO(
"Precaptured sample written to %s. File size: %lld bytes\n", filename.c_str(), (
long long)file.tellp());
273 ERROR(
"Could not open file %s.\n", filename.c_str());
279 ERROR(
"Error! Precaptured queue is empty.\n");
287 request_id_t
id = -1;
290 req->id = m_request_counter++;
291 req->filename = filename;
292 req->length = seconds;
293 req->time_remaining = seconds;
295 req->callback_data = cb_data;
296 m_requests.push_back(req);
297 compute_queue_size();
302 void music_id_client::compute_queue_size()
304 std::list<request_t *>::iterator iter;
305 unsigned int max_length = m_precapture_duration_seconds;
306 for(iter = m_requests.begin(); iter != m_requests.end(); iter++)
308 if(max_length < (*iter)->length)
310 max_length = (*iter)->length;
313 INFO(
"New max length for queue: %d\n", max_length);
314 m_queue_upper_limit_bytes = max_length * m_manager->
get_data_rate();
320 while(m_worker_thread_alive)
324 std::list<request_t *>::iterator iter = m_requests.begin();
325 while(iter != m_requests.end())
328 if(0 == request->time_remaining--)
330 INFO(
"Request %d is up.\n", request->id);
333 if(SOCKET_OUTPUT == m_delivery_method)
335 ret = grab_last_n_seconds(request->length);
339 ret = grab_last_n_seconds(request->filename, request->length);
343 ERROR(
"Failed to fulfil request %d.\n", (*iter)->id);
346 if(request->callback)
348 (request->callback)(request->callback_data, request->filename, ret);
351 iter = m_requests.erase(iter);
352 compute_queue_size();
366 static void write_32byte_little_endian(uint32_t data, std::ofstream &file)
369 buf[0] = (uint8_t)(0xFF & data);
370 buf[1] = (uint8_t)(0xFF & (data >> 8));
371 buf[2] = (uint8_t)(0xFF & (data >> 16));
372 buf[3] = (uint8_t)(0xFF & (data >> 24));
373 file.write((
const char *)&buf, 4);
377 static void write_32data_big_endian(uint32_t data, std::ofstream &file)
380 buf[3] = (uint8_t)(0xFF & data);
381 buf[2] = (uint8_t)(0xFF & (data >> 8));
382 buf[1] = (uint8_t)(0xFF & (data >> 16));
383 buf[0] = (uint8_t)(0xFF & (data >> 24));
384 file.write((
const char *)&buf, 4);
387 static void write_16byte_little_endian(uint16_t data, std::ofstream &file)
390 buf[0] = (uint8_t)(0xFF & data);
391 buf[1] = (uint8_t)(0xFF & (data >> 8));
392 file.write((
const char *)&buf, 2);
396 int music_id_client::write_queue_to_file(
const std::string &filename)
400 if(0 != m_queue.size())
402 std::ofstream file(filename.c_str(), std::ios::binary);
405 write_file_header(file, m_total_size);
406 std::list <audio_buffer *>::iterator iter;
407 for(iter = m_queue.begin(); iter != m_queue.end(); iter++)
409 file.write((
char *)(*iter)->m_start_ptr, (*iter)->m_size);
411 INFO(
"Sample written to %s.\n", filename.c_str());
415 ERROR(
"Could not open file %s.\n", filename.c_str());
421 ERROR(
"Error! queue is empty.\n");
428 int music_id_client::write_default_file_header(std::ofstream &file)
431 file.write(
"RIFF", 4);
432 uint32_t chunkSize = 0;
433 write_32byte_little_endian(chunkSize, file);
435 file.write(
"WAVE", 4);
438 file.write(
"fmt ", 4);
439 write_32byte_little_endian(16, file);
440 write_16byte_little_endian(1, file);
443 unsigned int bits_per_sample = 0;
444 unsigned int sampling_rate= 0;
445 unsigned int num_channels = 0;
446 unsigned int data_rate = 0;
449 get_individual_audio_parameters(m_output_properties, sampling_rate, bits_per_sample, num_channels);
450 data_rate = sampling_rate * num_channels * bits_per_sample / 8;
456 get_individual_audio_parameters(properties, sampling_rate, bits_per_sample, num_channels);
459 INFO(
"Header information: %d channel, %dHz, %d bits per sample audio.\n",
460 num_channels, sampling_rate, bits_per_sample);
461 write_16byte_little_endian((uint16_t)num_channels, file);
462 write_32byte_little_endian(sampling_rate, file);
463 write_32byte_little_endian(data_rate, file);
464 write_16byte_little_endian((uint16_t)(num_channels * bits_per_sample / 8), file);
465 write_16byte_little_endian((uint16_t)bits_per_sample, file);
468 file.write(
"data", 4);
469 write_32byte_little_endian(chunkSize, file);
472 int music_id_client::update_file_header_size(std::ofstream &file,
unsigned int data_size)
474 INFO(
"Finalizing file header. Payload size: %dkB.\n", (data_size/1024));
475 std::streampos original_position = file.tellp();
478 uint32_t chunkSize = 36 + data_size;
480 write_32byte_little_endian(chunkSize, file);
484 write_32byte_little_endian(data_size, file);
485 file.seekp(original_position);
489 static const unsigned int MAX_PRECAPTURE_LENGTH_SEC = 120;
493 return MAX_PRECAPTURE_LENGTH_SEC;
498 m_enable_wav_header_output = isEnabled;