mirror of
https://github.com/cjcliffe/CubicSDR.git
synced 2024-11-23 04:08:36 -05:00
initial audio sink file and thread handling rough-in
This commit is contained in:
parent
21dd062da0
commit
c202d99a2a
@ -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
27
src/audio/AudioFile.cpp
Normal 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
26
src/audio/AudioFile.h
Normal 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;
|
||||
|
||||
};
|
47
src/audio/AudioFileWAV.cpp
Normal file
47
src/audio/AudioFileWAV.cpp
Normal 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
26
src/audio/AudioFileWAV.h
Normal 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;
|
||||
|
||||
};
|
34
src/audio/AudioSinkFileThread.cpp
Normal file
34
src/audio/AudioSinkFileThread.cpp
Normal 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);
|
||||
}
|
24
src/audio/AudioSinkFileThread.h
Normal file
24
src/audio/AudioSinkFileThread.h
Normal 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;
|
||||
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user