-
Notifications
You must be signed in to change notification settings - Fork 58
/
Copy pathAudioContext.h
139 lines (112 loc) · 4.37 KB
/
AudioContext.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#pragma once
#include <condition_variable>
#include <mutex>
#include <thread>
#include "AudioTrack.h"
#define AUDIOCONTEXT_NUM_SAMPLE_BUFFERS 16
class AudioContext {
friend void PlayAudio(AudioContext*);
public:
struct SampleBuffer {
uint8_t* data;
int samples;
// Timestamp in seconds of last frame in buffer
float timestamp;
};
AudioContext();
~AudioContext();
inline bool HasLoadedAudio() const { return m_isDecoderRunning; }
inline bool IsAudioPlaying() const { return m_shouldPlayAudio; }
inline bool ShouldPlayNextTrack() const { return m_shouldPlayNextTrack; }
// Gets progress into song in seconds
float PlaybackProgress() const;
// Returns the TrackInfo for the currently playing track
// returns nullptr if nothing is playing
const TrackInfo* CurrentTrack() const { return m_currentTrack; }
void PlaybackStart();
void PlaybackPause();
// Stop playing audio and unload the file
void PlaybackStop();
// Seek to a new position in the song
void PlaybackSeek(float timestamp);
// Play the track given in info
// returns 0 on success
int PlayTrack(TrackInfo* info);
// Get TrackInfo struct for the given file
// returns 0 on success
int LoadTrack(std::string filepath, TrackInfo* info);
SampleBuffer sampleBuffers[AUDIOCONTEXT_NUM_SAMPLE_BUFFERS];
ssize_t samplesPerBuffer;
// Ring buffer of SampleBuffers
// Index of the last valid sample buffer
int lastSampleBuffer;
// The currently processed sample buffer
int currentSampleBuffer;
std::mutex sampleBuffersLock;
// Decoder waits for a buffer to be processed
std::condition_variable decoderWaitCondition;
// Decoder thread will block whilst it is not decoding an audio file
std::condition_variable decoderShouldRunCondition;
// Player thread will block whilst it is not playing audio samples
std::condition_variable playerShouldRunCondition;
int numValidBuffers;
private:
// Audio decoder loop
void DecodeAudio();
// Decodes a frame of audio and fills the next available buffer
void DecoderDecodeFrame(struct AVFrame* frame);
// Perform the requested seek to m_seekTimestamp
void DecoderDoSeek();
// Audio playeer loop.
// Reads buffers from sampleBuffers and sends them to the audio device
void PlayAudio();
// Get the next buffer that can hold samplesToWrite number of samples
// if the buffer after the write pointer is too full,
// increments the write pointer and returns the buffer after.
int DecoderGetNextSampleBufferOrWait(int samplesToWrite);
// A packet is considered invalid if we need to seek
// or the decoder is not marked as running
inline bool IsDecoderPacketInvalid() {
return m_requestSeek || !m_isDecoderRunning;
}
void GetTrackInfo(struct AVFormatContext* fmt, TrackInfo* info);
inline void FlushSampleBuffers() {
for (int i = 0; i < AUDIOCONTEXT_NUM_SAMPLE_BUFFERS; i++) {
sampleBuffers[i].samples = 0;
sampleBuffers[i].timestamp = 0;
}
}
// File descriptor for pcm output
int m_pcmOut;
int m_pcmSampleRate;
int m_pcmChannels;
int m_pcmBitDepth;
TrackInfo* m_currentTrack;
// Thread which writes PCM samples to the audio driver,
// reduces audio lag and prevents blocking the main thread
// so the decoder and GUI can run
std::thread m_playbackThread;
// Decoder runs parallel to playback and GUI threads
std::thread m_decoderThread;
// Held by the decoderThread whilst it is running
std::mutex m_decoderLock;
// Lock for m_shouldPlayAudio
std::mutex m_playerStatusLock;
// Lock for m_isDecoderRunning
std::mutex m_decoderStatusLock;
bool m_shouldThreadsDie = false;
bool m_isDecoderRunning = false;
bool m_shouldPlayNextTrack = false;
// Indicates to the player thread whether to not to play the audio
bool m_shouldPlayAudio = true;
bool m_requestSeek = false;
// Timestamp in seconds of where to seek to
float m_seekTimestamp;
// Last timestamp played by the playback thread
float m_lastTimestamp;
struct AVFormatContext* m_avfmt = nullptr;
struct AVCodecContext* m_avcodec = nullptr;
struct SwrContext* m_resampler = nullptr;
struct AVStream* m_currentStream = nullptr;
int m_currentStreamIndex = 0;
};