+
+ // Audio for the MJPEG stream. We don't resample; audio that's not in 48 kHz
+ // just gets dropped for now.
+ //
+ // Only bother doing MJPEG encoding if there are any connected clients
+ // that want the stream.
+ if (httpd.get_num_connected_multicam_clients() > 0 ||
+ httpd.get_num_connected_siphon_clients(card_index) > 0) {
+ vector<int32_t> converted_samples = convert_audio_to_fixed32(audio_frame.data + audio_offset, num_samples, audio_format, 2);
+ lock_guard<mutex> lock(card_mutex);
+ if (card->new_raw_audio.empty()) {
+ card->new_raw_audio = move(converted_samples);
+ } else {
+ // For raw audio, we don't really synchronize audio and video;
+ // we just put the audio in frame by frame, and if a video frame is
+ // dropped, we still keep the audio, which means it will be added
+ // to the beginning of the next frame. It would probably be better
+ // to move the audio pts earlier to show this, but most players can
+ // live with some jitter, and in a lot of ways, it's much nicer for
+ // Futatabi to have all audio locked to a video frame.
+ card->new_raw_audio.insert(card->new_raw_audio.end(), converted_samples.begin(), converted_samples.end());
+
+ // Truncate to one second, just to be sure we don't have infinite buildup in case of weirdness.
+ if (card->new_raw_audio.size() > OUTPUT_FREQUENCY * 2) {
+ size_t excess_samples = card->new_raw_audio.size() - OUTPUT_FREQUENCY * 2;
+ card->new_raw_audio.erase(card->new_raw_audio.begin(), card->new_raw_audio.begin() + excess_samples);
+ }
+ }
+ }