Skip to content

Commit

Permalink
fix audio save method
Browse files Browse the repository at this point in the history
  • Loading branch information
vpalmisano committed Apr 4, 2024
1 parent eec198b commit a7759ae
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 94 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@
"prom-client": "^14.2.0",
"puppeteer": "^19.11.1",
"puppeteer-core": "^19.11.1",
"puppeteer-extra": "^3.3.6",
"puppeteer-extra-plugin-stealth": "^2.11.2",
"puppeteer-intercept-and-modify-requests": "^1.3.0",
"sprintf-js": "^1.1.3",
Expand Down
2 changes: 1 addition & 1 deletion scripts/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ window.streamWriter = async (
}

return {
write(frameData, pts) {
write(frameData, pts = 0) {
//log('write', filename, frameData.byteLength, pts)
if (filename.endsWith('.ivf')) {
const data = new ArrayBuffer(12 + frameData.byteLength)
Expand Down
70 changes: 2 additions & 68 deletions scripts/get-user-media.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global log, loadScript, sleep, Tesseract, streamWriter, isSenderDisplayTrack */
/* global log, loadScript, sleep, Tesseract, isSenderDisplayTrack, saveVideoTrack */

const applyOverride = (constraints, override) => {
if (override) {
Expand Down Expand Up @@ -123,72 +123,6 @@ function collectMediaTracks(mediaStream) {
}) */
}

/**
* Save the MediaStream video track to disk.
* @param {MediaStreamTrack} videoTrack
*/
window.saveMediaStreamTrack = async (videoTrack, sendrecv, quality = 0.75) => {
const width = window.VIDEO_WIDTH
const height = window.VIDEO_HEIGHT
const frameRate = window.VIDEO_FRAMERATE
const fname = `${window.getParticipantName().split('_')[0]}-${sendrecv}_${
videoTrack.id
}.ivf`
log(`saveMediaStreamTrack ${fname} ${width}x${height} ${frameRate}fps`)
const writer = await streamWriter(fname, width, height, frameRate, 'MJPG')

const canvas = new OffscreenCanvas(width, height)
const ctx = canvas.getContext('2d')
let startTimestamp = -1
const writableStream = new window.WritableStream(
{
async write(videoFrame) {
const { timestamp, codedWidth, codedHeight } = videoFrame
if (!codedWidth || !codedHeight) {
return
}
const bitmap = await createImageBitmap(videoFrame)
try {
ctx.drawImage(bitmap, 0, 0, width, height)
const blob = await canvas.convertToBlob({
type: 'image/jpeg',
quality,
})
const data = await blob.arrayBuffer()
if (startTimestamp < 0) {
startTimestamp = timestamp
}
const pts = Math.round(
(frameRate * (timestamp - startTimestamp)) / 1000000,
)
/* log(
`writer ${data.byteLength} bytes timestamp=${
videoFrame.timestamp / 1000000
} pts=${pts}`,
) */
writer.write(data, pts)
} catch (err) {
log(`saveMediaStream error: ${err.message}`)
}
videoFrame.close()
bitmap.close()
},
close() {
writer.close()
},
abort(err) {
log('saveMediaStream error:', err)
},
},
new CountQueuingStrategy({ highWaterMark: frameRate * 2 }),
)

const trackProcessor = new window.MediaStreamTrackProcessor({
track: videoTrack,
})
trackProcessor.readable.pipeTo(writableStream)
}

/**
* Replaces the MediaStream video track with a new generated one with
* timestamp watermark.
Expand Down Expand Up @@ -437,7 +371,7 @@ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
if (window.PARAMS?.saveMediaStream) {
const videoTrack = mediaStream.getVideoTracks()[0]
if (videoTrack) {
await window.saveMediaStreamTrack(videoTrack, 'send')
await saveVideoTrack(videoTrack, 'send')
}
}

Expand Down
15 changes: 11 additions & 4 deletions scripts/peer-connection.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* global log, PeerConnections, handleTransceiverForInsertableStreams, handleTransceiverForPlayoutDelayHint, videoEndToEndDelayStats */
/* global log, PeerConnections, handleTransceiverForInsertableStreams, handleTransceiverForPlayoutDelayHint, videoEndToEndDelayStats, saveVideoTrack, saveAudioTrack */

const timestampInsertableStreams = !!window.PARAMS?.timestampInsertableStreams

Expand Down Expand Up @@ -131,10 +131,17 @@ window.RTCPeerConnection = function (conf, options) {
}

if (
window.PARAMS?.saveMediaStream &&
window.WEBRTC_STRESS_TEST_INDEX <= window.PARAMS?.saveMediaStream
window.PARAMS?.saveVideoTrack &&
window.WEBRTC_STRESS_TEST_INDEX <= window.PARAMS?.saveVideoTrack + 1
) {
await window.saveMediaStreamTrack(receiver.track, 'recv')
await saveVideoTrack(receiver.track, 'recv')
}
} else if (receiver.track.kind === 'audio') {
if (
window.PARAMS?.saveAudioTrack &&
window.WEBRTC_STRESS_TEST_INDEX <= window.PARAMS?.saveAudioTrack + 1
) {
await saveAudioTrack(receiver.track, 'recv')
}
}
}
Expand Down
107 changes: 107 additions & 0 deletions scripts/save-tracks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/* global log, streamWriter */

/**
* Save the video track to disk.
* @param {MediaStreamTrack} videoTrack
*/
window.saveVideoTrack = async (videoTrack, sendrecv, quality = 0.75) => {
const width = window.VIDEO_WIDTH
const height = window.VIDEO_HEIGHT
const frameRate = window.VIDEO_FRAMERATE
const fname = `${window.getParticipantName().split('_')[0]}-${sendrecv}_${
videoTrack.id
}.ivf`
log(`saveVideoTrack ${fname} ${width}x${height} ${frameRate}fps`)
const writer = await streamWriter(fname, width, height, frameRate, 'MJPG')

const canvas = new OffscreenCanvas(width, height)
const ctx = canvas.getContext('2d')
let startTimestamp = -1
const writableStream = new window.WritableStream(
{
async write(videoFrame) {
const { timestamp, codedWidth, codedHeight } = videoFrame
if (!codedWidth || !codedHeight) {
return
}
const bitmap = await createImageBitmap(videoFrame)
try {
ctx.drawImage(bitmap, 0, 0, width, height)
const blob = await canvas.convertToBlob({
type: 'image/jpeg',
quality,
})
const data = await blob.arrayBuffer()
if (startTimestamp < 0) {
startTimestamp = timestamp
}
const pts = Math.round(
(frameRate * (timestamp - startTimestamp)) / 1000000,
)
/* log(
`writer ${data.byteLength} bytes timestamp=${
videoFrame.timestamp / 1000000
} pts=${pts}`,
) */
writer.write(data, pts)
} catch (err) {
log(`saveVideoTrack error: ${err.message}`)
}
videoFrame.close()
bitmap.close()
},
close() {
writer.close()
},
abort(err) {
log('saveVideoTrack error:', err)
},
},
new CountQueuingStrategy({ highWaterMark: frameRate * 2 }),
)

const trackProcessor = new window.MediaStreamTrackProcessor({
track: videoTrack,
})
trackProcessor.readable.pipeTo(writableStream)
}

/**
* Save the audio track to disk.
* @param {MediaStreamTrack} audioTrack
*/
window.saveAudioTrack = async (audioTrack, sendrecv) => {
const fname = `${window.getParticipantName().split('_')[0]}-${sendrecv}_${
audioTrack.id
}.f32le.raw`
log(`saveAudioTrack ${fname}`)
const writer = await streamWriter(fname)

const writableStream = new window.WritableStream(
{
async write(frame) {
const { numberOfFrames } = frame
try {
const data = new Float32Array(numberOfFrames)
frame.copyTo(data, { planeIndex: 0 })
writer.write(data)
} catch (err) {
log(`saveAudioTrack error: ${err.message}`)
}
frame.close()
},
close() {
writer.close()
},
abort(err) {
log('saveAudioTrack error:', err)
},
},
new CountQueuingStrategy({ highWaterMark: 100 }),
)

const trackProcessor = new window.MediaStreamTrackProcessor({
track: audioTrack,
})
trackProcessor.readable.pipeTo(writableStream)
}
14 changes: 3 additions & 11 deletions src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { LoremIpsum } from 'lorem-ipsum'
import NodeCache from 'node-cache'
import os from 'os'
import path from 'path'
import * as vanillaPuppeteer from 'puppeteer'
import puppeteer, {
Browser,
BrowserContext,
Expand All @@ -18,15 +17,10 @@ import puppeteer, {
Metrics,
Page,
} from 'puppeteer-core'
import { addExtra } from 'puppeteer-extra'
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
import type { Interception } from 'puppeteer-intercept-and-modify-requests'
import { RequestInterceptionManager } from 'puppeteer-intercept-and-modify-requests'
import { gunzipSync } from 'zlib'

const puppeteerExtra = addExtra(vanillaPuppeteer)
puppeteerExtra.use(StealthPlugin())

// For nexe bundler.
require('puppeteer-extra-plugin-stealth/evasions/chrome.app')
require('puppeteer-extra-plugin-stealth/evasions/chrome.csi')
Expand Down Expand Up @@ -690,7 +684,7 @@ export class Session extends EventEmitter {
}

// Create process wrapper.
if (this.throttleIndex > -1) {
if (this.throttleIndex > -1 && os.platform() === 'linux') {
const mark = this.throttleIndex + 1
const executableWrapperPath = `/tmp/webrtcperf-launcher-${mark}`
const group = `webrtcperf${mark}`
Expand Down Expand Up @@ -737,10 +731,7 @@ exec sg ${group} -c /tmp/webrtcperf-launcher-${mark}-browser`,

try {
// log.debug('defaultArgs:', puppeteer.defaultArgs());
this.browser = (await (process.env.USE_PUPPETEER_EXTRA === 'true'
? puppeteerExtra
: puppeteer
).launch({
this.browser = (await puppeteer.launch({
headless: this.display ? false : 'new',
executablePath,
handleSIGINT: false,
Expand Down Expand Up @@ -966,6 +957,7 @@ window.SERVER_USE_HTTPS = ${this.serverUseHttps};
'scripts/end-to-end-stats.js',
'scripts/playout-delay-hint.js',
'scripts/page-stats.js',
'scripts/save-tracks.js',
]) {
const filePath = resolvePackagePath(name)
log.debug(`loading ${name} script from: ${filePath}`)
Expand Down
3 changes: 3 additions & 0 deletions src/throttle.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import JSON5 from 'json5'
import os from 'os'

import { logger, runShellCommand } from './utils'

Expand Down Expand Up @@ -235,6 +236,7 @@ sudo -n tc filter add dev ${device} \
* @param config A JSON5 configuration parsed as {@link ThrottleConfig}.
*/
export async function startThrottle(config: string): Promise<void> {
if (os.platform() !== 'linux') return
try {
throttleConfig = JSON5.parse(config) as ThrottleConfig[]
log.info('Starting throttle with config:', throttleConfig)
Expand All @@ -251,6 +253,7 @@ export async function startThrottle(config: string): Promise<void> {
* Stops the network throttle.
*/
export async function stopThrottle(): Promise<void> {
if (os.platform() !== 'linux') return
try {
log.info('Stopping throttle')
await cleanup()
Expand Down
9 changes: 0 additions & 9 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6613,15 +6613,6 @@ puppeteer-extra-plugin@^3.2.3:
debug "^4.1.1"
merge-deep "^3.0.1"

puppeteer-extra@^3.3.6:
version "3.3.6"
resolved "https://registry.yarnpkg.com/puppeteer-extra/-/puppeteer-extra-3.3.6.tgz#fc16ff396aae52664842da9a557ea8fa51eaa8b7"
integrity sha512-rsLBE/6mMxAjlLd06LuGacrukP2bqbzKCLzV1vrhHFavqQE/taQ2UXv3H5P0Ls7nsrASa+6x3bDbXHpqMwq+7A==
dependencies:
"@types/debug" "^4.1.0"
debug "^4.1.1"
deepmerge "^4.2.2"

puppeteer-intercept-and-modify-requests@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/puppeteer-intercept-and-modify-requests/-/puppeteer-intercept-and-modify-requests-1.3.0.tgz#ed7d60bfd7016fae962e6be01e4a1586664d3dfa"
Expand Down

0 comments on commit a7759ae

Please sign in to comment.