Skip to content

Commit af83e66

Browse files
committed
Audio fixes
- For devices with >2 channels, only use first 2 when loading into ffmpeg - If output pipeline only has 1 audio source, don't use audio mixer
1 parent ce6ebd6 commit af83e66

File tree

7 files changed

+219
-159
lines changed

7 files changed

+219
-159
lines changed

apps/web/app/s/[videoId]/_components/AuthOverlay.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { signIn } from "next-auth/react";
1010
import { useId, useState } from "react";
1111
import { toast } from "sonner";
1212
import { trackEvent } from "@/app/utils/analytics";
13-
import OtpForm from "./OtpForm";
1413
import { usePublicEnv } from "@/utils/public-env";
14+
import OtpForm from "./OtpForm";
1515

1616
interface AuthOverlayProps {
1717
isOpen: boolean;

apps/web/app/s/[videoId]/_components/Sidebar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export const Sidebar = forwardRef<{ scrollToBottom: () => void }, SidebarProps>(
9797
: !(
9898
videoSettings?.disableTranscript ??
9999
data.orgSettings?.disableTranscript
100-
)
100+
)
101101
? "transcript"
102102
: "activity";
103103

crates/media-info/src/lib.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub enum AudioInfoError {
2424
}
2525

2626
impl AudioInfo {
27-
pub const MAX_AUDIO_CHANNELS: u16 = 8;
27+
pub const MAX_AUDIO_CHANNELS: u16 = 16;
2828

2929
pub const fn new(
3030
sample_format: Sample,
@@ -133,18 +133,26 @@ impl AudioInfo {
133133
frame
134134
}
135135

136-
pub fn wrap_frame(&self, data: &[u8]) -> frame::Audio {
136+
pub fn wrap_frame_with_max_channels(&self, data: &[u8], max_channels: usize) -> frame::Audio {
137+
let out_channels = self.channels.min(max_channels);
138+
137139
let sample_size = self.sample_size();
138140
let interleaved_chunk_size = sample_size * self.channels;
139141
let samples = data.len() / interleaved_chunk_size;
140142

141-
let mut frame = frame::Audio::new(self.sample_format, samples, self.channel_layout());
143+
let mut frame = frame::Audio::new(
144+
self.sample_format,
145+
samples,
146+
ChannelLayout::default(out_channels as i32),
147+
);
142148
frame.set_rate(self.sample_rate);
143149

144150
if self.channels == 0 {
145151
unreachable!()
146-
} else if self.channels == 1 || frame.is_packed() {
152+
} else if self.channels == 1 || (frame.is_packed() && self.channels <= max_channels) {
147153
frame.data_mut(0)[0..data.len()].copy_from_slice(data)
154+
} else if frame.is_packed() && self.channels > max_channels {
155+
todo!();
148156
} else {
149157
// cpal *always* returns interleaved data (i.e. the first sample from every channel, followed
150158
// by the second sample from every channel, et cetera). Many audio codecs work better/primarily
@@ -155,7 +163,7 @@ impl AudioInfo {
155163
let start = chunk_index * sample_size;
156164
let end = start + sample_size;
157165

158-
for channel in 0..self.channels {
166+
for channel in 0..self.channels.min(max_channels) {
159167
let channel_start = channel * sample_size;
160168
let channel_end = channel_start + sample_size;
161169
frame.data_mut(channel)[start..end]
@@ -166,6 +174,15 @@ impl AudioInfo {
166174

167175
frame
168176
}
177+
178+
pub fn wrap_frame(&self, data: &[u8]) -> frame::Audio {
179+
self.wrap_frame_with_max_channels(data, self.channels)
180+
}
181+
182+
pub fn with_max_channels(mut self, channels: u16) -> Self {
183+
self.channels = self.channels.min(channels as usize);
184+
self
185+
}
169186
}
170187

171188
pub enum RawVideoFormat {

crates/recording/examples/recording-cli.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
use cap_recording::{screen_capture::ScreenCaptureTarget, *};
1+
use cap_recording::{feeds::*, screen_capture::ScreenCaptureTarget, *};
2+
use kameo::Actor as _;
23
use scap_targets::Display;
3-
use std::time::Duration;
4+
use std::{sync::Arc, time::Duration};
45
use tracing::*;
56

67
#[tokio::main]
@@ -37,23 +38,22 @@ pub async fn main() {
3738
// .await
3839
// .unwrap();
3940

40-
// let (error_tx, _) = flume::bounded(1);
41-
// let mic_feed = MicrophoneFeed::spawn(MicrophoneFeed::new(error_tx));
42-
43-
// mic_feed
44-
// .ask(microphone::SetInput {
45-
// label:
46-
// // MicrophoneFeed::list()
47-
// // .into_iter()
48-
// // .find(|(k, _)| k.contains("Focusrite"))
49-
// MicrophoneFeed::default()
50-
// .map(|v| v.0)
51-
// .unwrap(),
52-
// })
53-
// .await
54-
// .unwrap()
55-
// .await
56-
// .unwrap();
41+
let (error_tx, _) = flume::bounded(1);
42+
let mic_feed = MicrophoneFeed::spawn(MicrophoneFeed::new(error_tx));
43+
44+
mic_feed
45+
.ask(microphone::SetInput {
46+
label: MicrophoneFeed::list()
47+
.into_iter()
48+
.find(|(k, _)| k.contains("BlackHole"))
49+
// MicrophoneFeed::default_device()
50+
.map(|v| v.0)
51+
.unwrap(),
52+
})
53+
.await
54+
.unwrap()
55+
.await
56+
.unwrap();
5757

5858
tokio::time::sleep(Duration::from_millis(10)).await;
5959

@@ -63,10 +63,11 @@ pub async fn main() {
6363
id: Display::primary().id(),
6464
},
6565
)
66-
// .with_system_audio(true)
66+
.with_system_audio(true)
6767
// .with_camera_feed(std::sync::Arc::new(
6868
// camera_feed.ask(feeds::camera::Lock).await.unwrap(),
6969
// ))
70+
.with_mic_feed(Arc::new(mic_feed.ask(microphone::Lock).await.unwrap()))
7071
.build(
7172
#[cfg(target_os = "macos")]
7273
cidre::sc::ShareableContent::current().await.unwrap(),

0 commit comments

Comments
 (0)