Skip to content

Commit cc111d5

Browse files
committed
Merge branch 'main' into package-hang-ui
2 parents b3fe482 + d01382b commit cc111d5

File tree

1 file changed

+98
-10
lines changed

1 file changed

+98
-10
lines changed

rs/hang-c/src/lib.rs

Lines changed: 98 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@ use tokio::runtime::Runtime;
22
use url::Url;
33

44
use bytes::Bytes;
5-
use hang::catalog::{Video, VideoConfig, H264};
5+
use hang::catalog::{Audio, AudioConfig, Video, VideoConfig, AAC, H264};
66
use hang::model::{Frame, Timestamp, TrackProducer};
77
use hang::{Catalog, CatalogProducer};
88
use moq_lite::{BroadcastProducer, Track};
99
use std::ffi::CStr;
1010
use std::os::raw::c_char;
1111
use std::sync::atomic::{AtomicBool, Ordering};
12-
use std::sync::{Mutex, OnceLock};
12+
use std::sync::Mutex;
1313
use std::thread::JoinHandle;
1414
use std::{collections::HashMap, time::Duration};
1515

16-
static IMPORT: OnceLock<Mutex<ImportJoy>> = OnceLock::new();
17-
static HANDLE: OnceLock<Mutex<JoinHandle<()>>> = OnceLock::new();
16+
static IMPORT: Mutex<Option<ImportJoy>> = Mutex::new(None);
17+
static HANDLE: Mutex<Option<JoinHandle<()>>> = Mutex::new(None);
1818
static RUNNING: AtomicBool = AtomicBool::new(false);
1919

2020
/// # Safety
@@ -63,12 +63,22 @@ pub unsafe extern "C" fn hang_start_from_c(
6363
});
6464
});
6565

66-
let _ = HANDLE.set(Mutex::new(handle));
66+
if let Ok(mut guard) = HANDLE.lock() {
67+
*guard = Some(handle);
68+
}
6769
}
6870

6971
#[no_mangle]
7072
pub extern "C" fn hang_stop_from_c() {
7173
RUNNING.store(false, Ordering::Relaxed);
74+
if let Ok(mut guard) = HANDLE.lock() {
75+
if let Some(handle) = guard.take() {
76+
let _ = handle.join();
77+
}
78+
}
79+
if let Ok(mut guard) = IMPORT.lock() {
80+
*guard = None;
81+
}
7282
}
7383

7484
/// # Safety
@@ -83,14 +93,34 @@ pub unsafe extern "C" fn hang_write_video_packet_from_c(data: *const u8, size: u
8393
return;
8494
}
8595

86-
if let Some(import_mutex) = IMPORT.get() {
87-
if let Ok(mut import) = import_mutex.lock() {
96+
if let Ok(mut guard) = IMPORT.lock() {
97+
if let Some(import) = guard.as_mut() {
8898
// SAFETY: Caller of hang_write_video_packet_from_c guarantees data is valid
8999
import.write_video_frame(data, size, keyframe > 0, dts);
90100
}
91101
}
92102
}
93103

104+
/// # Safety
105+
///
106+
/// The caller must ensure that:
107+
/// - `data` points to a valid buffer of at least `size` bytes
108+
/// - The buffer remains valid for the duration of this function call
109+
#[no_mangle]
110+
pub unsafe extern "C" fn hang_write_audio_packet_from_c(data: *const u8, size: usize, dts: u64) {
111+
// Validate pointer and size
112+
if data.is_null() || size == 0 {
113+
return;
114+
}
115+
116+
if let Ok(mut guard) = IMPORT.lock() {
117+
if let Some(import) = guard.as_mut() {
118+
// SAFETY: Caller of hang_write_audio_packet_from_c guarantees data is valid
119+
import.write_audio_frame(data, size, dts);
120+
}
121+
}
122+
}
123+
94124
pub async fn client(url: Url, name: String) -> anyhow::Result<()> {
95125
let broadcast = moq_lite::Broadcast::produce();
96126
let config = moq_native::ClientConfig::default();
@@ -104,7 +134,9 @@ pub async fn client(url: Url, name: String) -> anyhow::Result<()> {
104134

105135
let mut import = ImportJoy::new(broadcast.producer);
106136
import.init();
107-
let _ = IMPORT.set(Mutex::new(import));
137+
if let Ok(mut guard) = IMPORT.lock() {
138+
*guard = Some(import);
139+
}
108140

109141
origin.producer.publish_broadcast(&name, broadcast.consumer);
110142

@@ -147,11 +179,12 @@ impl ImportJoy {
147179
pub fn init(&mut self) {
148180
// Produce the catalog
149181
let mut video_renditions = HashMap::new();
182+
let mut audio_renditions = HashMap::new();
150183

151184
let (track_name, config) = Self::init_video();
152185
let track = Track {
153186
name: track_name.clone(),
154-
priority: 2,
187+
priority: 1,
155188
};
156189
let track_produce = track.produce();
157190
self.broadcast.insert_track(track_produce.consumer);
@@ -162,14 +195,33 @@ impl ImportJoy {
162195
if !video_renditions.is_empty() {
163196
let video = Video {
164197
renditions: video_renditions,
165-
priority: 2,
198+
priority: 1,
166199
display: None,
167200
rotation: None,
168201
flip: None,
169202
};
170203
self.catalog.set_video(Some(video));
171204
}
172205

206+
let (track_name, config) = Self::init_audio();
207+
let track = Track {
208+
name: track_name.clone(),
209+
priority: 2,
210+
};
211+
let track_produce = track.produce();
212+
self.broadcast.insert_track(track_produce.consumer);
213+
audio_renditions.insert(track_name, config);
214+
215+
self.tracks.insert(1, track_produce.producer.into());
216+
217+
if !audio_renditions.is_empty() {
218+
let audio = Audio {
219+
renditions: audio_renditions,
220+
priority: 2,
221+
};
222+
self.catalog.set_audio(Some(audio));
223+
}
224+
173225
self.catalog.publish();
174226
}
175227

@@ -197,6 +249,20 @@ impl ImportJoy {
197249
(name, config)
198250
}
199251

252+
pub fn init_audio() -> (String, AudioConfig) {
253+
let name = String::from("audio1");
254+
255+
let config = AudioConfig {
256+
codec: AAC { profile: 2 }.into(),
257+
sample_rate: 48000,
258+
channel_count: 2,
259+
bitrate: Some(128000),
260+
description: None,
261+
};
262+
263+
(name, config)
264+
}
265+
200266
/// # Safety
201267
///
202268
/// The caller must ensure that `data` points to a valid buffer of at least `size` bytes
@@ -225,4 +291,26 @@ impl ImportJoy {
225291

226292
track.write(frame);
227293
}
294+
295+
/// # Safety
296+
///
297+
/// The caller must ensure that `data` points to a valid buffer of at least `size` bytes
298+
pub unsafe fn write_audio_frame(&mut self, data: *const u8, size: usize, dts: u64) {
299+
let Some(track) = self.tracks.get_mut(&1) else {
300+
return;
301+
};
302+
303+
// Use copy_from_slice to own the data, avoiding use-after-free when C caller frees the buffer
304+
let payload = Bytes::copy_from_slice(std::slice::from_raw_parts(data, size));
305+
306+
let timestamp = Timestamp::from_micros(dts);
307+
308+
let frame = Frame {
309+
timestamp,
310+
keyframe: false,
311+
payload,
312+
};
313+
314+
track.write(frame);
315+
}
228316
}

0 commit comments

Comments
 (0)