initial audio sink file and thread handling rough-in

This commit is contained in:
Charles J. Cliffe 2017-09-26 23:25:55 -04:00
parent 21dd062da0
commit c202d99a2a
11 changed files with 227 additions and 35 deletions

View File

@ -348,6 +348,9 @@ SET (cubicsdr_sources
src/modules/modem/analog/ModemUSB.cpp
src/audio/AudioThread.cpp
src/audio/AudioSinkThread.cpp
src/audio/AudioSinkFileThread.cpp
src/audio/AudioFile.cpp
src/audio/AudioFileWAV.cpp
src/util/Gradient.cpp
src/util/Timer.cpp
src/util/MouseTracker.cpp
@ -453,6 +456,9 @@ SET (cubicsdr_headers
src/modules/modem/analog/ModemUSB.h
src/audio/AudioThread.h
src/audio/AudioSinkThread.h
src/audio/AudioSinkFileThread.h
src/audio/AudioFile.h
src/audio/AudioFileWAV.h
src/util/Gradient.h
src/util/Timer.h
src/util/ThreadBlockingQueue.h

27
src/audio/AudioFile.cpp Normal file
View File

@ -0,0 +1,27 @@
// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+
#include "AudioFile.h"
#include "CubicSDR.h"
AudioFile::AudioFile() {
}
AudioFile::~AudioFile() {
}
void AudioFile::setOutputFileName(std::string filename) {
filenameBase = filename;
}
std::string AudioFile::getOutputFileName() {
std::string recPath = wxGetApp().getConfig()->getRecordingPath();
// TODO: Handle invalid chars, etc..
std::string filenameBaseSafe = filenameBase;
return recPath + filePathSeparator + filenameBaseSafe + getSuffix() + "." + getExtension();
}

26
src/audio/AudioFile.h Normal file
View File

@ -0,0 +1,26 @@
// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+
#pragma once
#include "AudioThread.h"
class AudioFile
{
public:
AudioFile();
virtual ~AudioFile();
virtual void setOutputFileName(std::string filename);
virtual std::string getExtension() = 0;
virtual std::string getSuffix() = 0;
virtual std::string getOutputFileName();
virtual bool writeToFile(AudioThreadInputPtr input) = 0;
virtual bool closeFile() = 0;
protected:
std::string filenameBase;
};

View File

@ -0,0 +1,47 @@
// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+
#include "AudioFileWAV.h"
// #include "WavFileFormatHandlerStuff.h"
AudioFileWAV::AudioFileWAV() : AudioFile() {
}
AudioFileWAV::~AudioFileWAV() {
}
std::string AudioFileWAV::getExtension()
{
return "wav";
}
std::string AudioFileWAV::getSuffix()
{
return suffix;
}
bool AudioFileWAV::writeToFile(AudioThreadInputPtr input)
{
if (!outputFileStream.is_open()) {
suffix = "";
std::string ofName = getOutputFileName();
// Check if file exists, sequence the suffix?
outputFileStream.open(ofName.c_str(), std::ios::out | std::ios::binary);
}
// write input data to wav file
return true;
}
bool AudioFileWAV::closeFile()
{
if (outputFileStream.is_open()) {
outputFileStream.close();
}
return true;
}

26
src/audio/AudioFileWAV.h Normal file
View File

@ -0,0 +1,26 @@
// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+
#pragma once
#include "AudioFile.h"
#include <fstream>
class AudioFileWAV : public AudioFile {
public:
AudioFileWAV();
~AudioFileWAV();
std::string getExtension();
std::string getSuffix();
bool writeToFile(AudioThreadInputPtr input);
bool closeFile();
protected:
std::ofstream outputFileStream;
std::string suffix;
};

View File

@ -0,0 +1,34 @@
// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+
#include "AudioSinkFileThread.h"
AudioSinkFileThread::AudioSinkFileThread() : AudioSinkThread() {
}
AudioSinkFileThread::~AudioSinkFileThread() {
if (outputFileHandler != nullptr) {
outputFileHandler->closeFile();
}
}
void AudioSinkFileThread::sink(AudioThreadInputPtr input) {
if (!outputFileHandler) {
return;
}
// forward to output file handler
outputFileHandler->writeToFile(input);
}
void AudioSinkFileThread::inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps) {
// close, set new parameters, adjust file name sequence and re-open?
if (!outputFileHandler) {
return;
}
}
void AudioSinkFileThread::setOutput(AudioFile * output) {
outputFileHandler = output;
outputFileHandler->setOutputFileName(sinkName);
}

View File

@ -0,0 +1,24 @@
// Copyright (c) Charles J. Cliffe
// SPDX-License-Identifier: GPL-2.0+
#pragma once
#include "AudioSinkThread.h"
#include "AudioFile.h"
class AudioSinkFileThread : public AudioSinkThread {
public:
AudioSinkFileThread();
~AudioSinkFileThread();
void sink(AudioThreadInputPtr input);
void inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps);
void setOutput(AudioFile *output);
protected:
AudioFile *outputFileHandler = nullptr;
};

View File

@ -5,19 +5,16 @@
#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000)
AudioSinkThread::AudioSinkThread()
{
AudioSinkThread::AudioSinkThread() {
inputQueuePtr = std::make_shared<AudioThreadInputQueue>();
setInputQueue("input", inputQueuePtr);
}
AudioSinkThread::~AudioSinkThread()
{
AudioSinkThread::~AudioSinkThread() {
}
void AudioSinkThread::run()
{
void AudioSinkThread::run() {
#ifdef __APPLE__
pthread_t tID = pthread_self(); // ID of this thread
int priority = sched_get_priority_max(SCHED_RR) - 1;
@ -46,38 +43,18 @@ void AudioSinkThread::run()
inputRef.sampleRate = inp->sampleRate;
}
}
}
//Thread termination, prevent fancy things to happen, lock the whole thing:
std::lock_guard<std::recursive_mutex> lock(m_mutex);
// Drain any remaining inputs, with a non-blocking pop
void AudioSinkThread::terminate() {
IOThread::terminate();
inputQueuePtr->flush();
}
void AudioSinkThread::terminate()
{
IOThread::terminate();
}
void AudioSinkThread::sink(AudioThreadInputPtr * input)
{
// do something with the audio data
}
void AudioSinkThread::inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps)
{
// handle changes in stream properties
}
void AudioSinkThread::setSinkName(std::string sinkName_in)
{
void AudioSinkThread::setSinkName(std::string sinkName_in) {
sinkName = sinkName_in;
}
std::string AudioSinkThread::getSinkName()
{
std::string AudioSinkThread::getSinkName() {
return sinkName;
}

View File

@ -15,8 +15,8 @@ public:
virtual void run();
virtual void terminate();
virtual void sink(AudioThreadInputPtr *input);
virtual void inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps);
virtual void sink(AudioThreadInputPtr input) = 0;
virtual void inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps) = 0;
virtual void setSinkName(std::string sinkName_in);
virtual std::string getSinkName();
@ -25,4 +25,5 @@ protected:
std::recursive_mutex m_mutex;
AudioThreadInputQueuePtr inputQueuePtr;
std::string sinkName;
};

View File

@ -106,6 +106,7 @@ DemodulatorInstance::~DemodulatorInstance() {
delete demodulatorPreThread;
delete demodulatorThread;
delete audioThread;
delete audioSinkThread;
break;
}
@ -181,6 +182,10 @@ void DemodulatorInstance::terminate() {
// std::cout << "Terminating demodulator preprocessor thread.." << std::endl;
demodulatorPreThread->terminate();
if (audioSinkThread != nullptr) {
audioSinkThread->terminate();
}
//that will actually unblock the currently blocked push().
pipeIQInputData->flush();
pipeAudioData->flush();
@ -204,6 +209,7 @@ bool DemodulatorInstance::isTerminated() {
bool audioTerminated = audioThread->isTerminated();
bool demodTerminated = demodulatorThread->isTerminated();
bool preDemodTerminated = demodulatorPreThread->isTerminated();
bool audioSinkTerminated = (audioSinkThread == nullptr) || audioSinkThread->isTerminated();
//Cleanup the worker threads, if the threads are indeed terminated.
// threads are linked as t_PreDemod ==> t_Demod ==> t_Audio
@ -240,14 +246,27 @@ bool DemodulatorInstance::isTerminated() {
if (audioTerminated) {
if (t_Audio) {
#ifdef __APPLE__
pthread_join(t_PreDemod, NULL);
#else
t_Audio->join();
delete t_Audio;
#endif
t_Audio = nullptr;
}
}
bool terminated = audioTerminated && demodTerminated && preDemodTerminated;
if (audioSinkTerminated) {
if (t_AudioSink != nullptr) {
t_AudioSink->join();
delete t_AudioSink;
t_AudioSink = nullptr;
}
}
bool terminated = audioTerminated && demodTerminated && preDemodTerminated && audioSinkTerminated;
return terminated;
}

View File

@ -11,6 +11,7 @@
#include "ModemDigital.h"
#include "ModemAnalog.h"
#include "AudioThread.h"
#include "AudioSinkThread.h"
#if ENABLE_DIGITAL_LAB
#include "DigitalConsole.h"
@ -139,6 +140,10 @@ private:
DemodulatorThread *demodulatorThread;
DemodulatorThreadControlCommandQueuePtr threadQueueControl;
AudioSinkThread *audioSinkThread = nullptr;
std::thread *t_AudioSink = nullptr;
AudioThreadInputQueuePtr audioSinkInputQueue;
//protects child thread creation and termination
std::recursive_mutex m_thread_control_mutex;