@@ -204,8 +204,14 @@ namespace Plugin {
204204 _voiceHandler = nullptr ;
205205 }
206206
207+ if (_buffer != nullptr ) {
208+ delete _buffer;
209+ _buffer = nullptr ;
210+ }
211+
207212 _service->Release ();
208213 _service = nullptr ;
214+
209215 }
210216 }
211217
@@ -437,6 +443,56 @@ namespace Plugin {
437443
438444 _gattRemote->Decoder (_configLine);
439445
446+ if (_buffer != nullptr ) {
447+ delete _buffer;
448+ _buffer = nullptr ;
449+ }
450+
451+ Config config;
452+ config.FromString (_configLine);
453+
454+ Exchange::IVoiceProducer::IProfile* profile = _gattRemote->SelectedProfile ();
455+ ASSERT (profile != nullptr );
456+
457+ const uint16_t maxChunkDuration = std::max (config.AudioChunkSize .Value (), config.FirstAudioChunkSize .Value ());
458+
459+ if (maxChunkDuration != 0 ) {
460+ // If buffer size is not specified, then set it based on the configured chunk sizes
461+ const uint32_t maxDuration = std::max (config.AudioBufferSize .Value (), (maxChunkDuration + config.AudioChunkSize .Value ()));
462+ const uint32_t bufferSize = TimeToBytes (maxDuration, profile);
463+ _firstAudioChunkSize = TimeToBytes (config.FirstAudioChunkSize .Value (), profile);
464+ _audioChunkSize = TimeToBytes (config.AudioChunkSize .Value (), profile);
465+
466+ // Some sanity...
467+ ASSERT (bufferSize <= (512 * 1024 ));
468+ ASSERT (_firstAudioChunkSize <= (512 * 1024 ));
469+ ASSERT (_audioChunkSize <= (512 * 1024 ));
470+
471+ _buffer = new RingBufferType<uint32_t >(bufferSize);
472+ ASSERT (_buffer != nullptr );
473+
474+ TRACE (Trace::Information, (_T (" Audio buffer size is %d bytes (%d ms)" ), bufferSize, maxDuration));
475+
476+ if (_firstAudioChunkSize != 0 ) {
477+ TRACE (Trace::Information, (_T (" First audio chunk size is %d bytes (%d ms)" ), _firstAudioChunkSize, config.FirstAudioChunkSize .Value ()));
478+ }
479+ else {
480+ TRACE (Trace::Information, (_T (" Audio will not be pre-buffered" )));
481+ }
482+
483+ if (_audioChunkSize != 0 ) {
484+ TRACE (Trace::Information, (_T (" Audio chunk size is %d bytes (%d ms)" ), _audioChunkSize, config.AudioChunkSize .Value ()));
485+ }
486+ else {
487+ TRACE (Trace::Information, (_T (" Audio chunks will not be buffered" )));
488+ }
489+ }
490+ else {
491+ TRACE (Trace::Information, (_T (" Audio buffering is disabled" )));
492+ }
493+
494+ profile->Release ();
495+
440496 // Store the settings, if not already done..
441497 Core::File settingsFile (_service->PersistentPath () + _gattRemote->Address () + _T (" .json" ));
442498 if ( (settingsFile.Exists () == false ) && (settingsFile.Create () == true ) ) {
@@ -458,6 +514,12 @@ namespace Plugin {
458514
459515 _adminLock.Lock ();
460516
517+ _sequence = 0 ;
518+
519+ if (_buffer != nullptr ) {
520+ _buffer->Reset ();
521+ }
522+
461523 if (_voiceHandler != nullptr ) {
462524 _voiceHandler->Start (profile);
463525 }
@@ -494,6 +556,11 @@ namespace Plugin {
494556
495557 _adminLock.Lock ();
496558
559+ if ((_buffer != nullptr ) && (_sequence != 0 )) {
560+ // Push out whatever is left (but only if a complete first chunk went out)
561+ SendOut (_buffer->Used ());
562+ }
563+
497564 if (_voiceHandler != nullptr ) {
498565 _voiceHandler->Stop ();
499566 }
@@ -507,7 +574,6 @@ namespace Plugin {
507574 _recorder.Close ();
508575 }
509576
510-
511577 TRACE (Trace::Information, (_T (" Audio transmission: end" )));
512578 }
513579 }
@@ -516,19 +582,64 @@ namespace Plugin {
516582 {
517583 _adminLock.Lock ();
518584
585+ const uint32_t chunkSize = ((_firstAudioChunkSize != 0 ) && (_sequence == 0 )? _firstAudioChunkSize : _audioChunkSize);
586+
587+ if (chunkSize != 0 ) {
588+ ASSERT (_buffer != nullptr );
589+
590+ if (_buffer->Free () < length) {
591+ const uint32_t newSize = std::max ((_buffer->Capacity () * 2 ), (_buffer->Capacity () + length));
592+ TRACE (Trace::Warning, (_T (" Ring buffer size is too small, resizing from %d to %d bytes!" ), _buffer->Capacity (), newSize));
593+ _buffer->Resize (newSize);
594+ }
595+
596+ const uint32_t written = _buffer->Push (length, dataBuffer);
597+ DEBUG_VARIABLE (written);
598+ ASSERT (written == length);
599+
600+ while (_buffer->Used () >= chunkSize) {
601+ SendOut (chunkSize);
602+ }
603+ }
604+ else if (length > 0 ) {
605+ SendOut (seq, length, dataBuffer);
606+ }
607+
608+ if (_recorder.IsOpen () == true ) {
609+ _recorder.Write (length, dataBuffer);
610+ }
611+
612+ _adminLock.Unlock ();
613+ }
614+
615+ void BluetoothRemoteControl::SendOut (const uint32_t seq, const uint32_t length, const uint8_t dataBuffer[])
616+ {
617+ ASSERT (length != 0 );
618+ ASSERT (dataBuffer != nullptr );
619+
519620 if (_voiceHandler != nullptr ) {
520621 _voiceHandler->Data (seq, dataBuffer, length);
521622 }
522623 else {
523624 string frame;
524625 Core::ToString (dataBuffer, length, true , frame);
525- event_audioframe (seq, frame);
626+ event_audioframe (seq, length, frame);
526627 }
628+ }
527629
528- _adminLock.Unlock ();
630+ void BluetoothRemoteControl::SendOut (const uint32_t length)
631+ {
632+ if (length != 0 ) {
633+ uint8_t * buffer = static_cast <uint8_t *>(ALLOCA (length));
634+ const uint32_t read = _buffer->Pop (length, buffer);
529635
530- if (_recorder.IsOpen () == true ) {
531- _recorder.Write (length, dataBuffer);
636+ if (read > 0 ) {
637+ SendOut (_sequence, read, buffer);
638+ _sequence++;
639+ }
640+ else if (read < length) {
641+ ASSERT (!" not enouqh data" );
642+ }
532643 }
533644 }
534645
0 commit comments