6#include <private/qplatformmediadevices_p.h>
7#include <private/qplatformmediaintegration_p.h>
11#include <private/qstdweb_p.h>
12#include <QtCore/QIODevice>
30 if (m_outputTarget->
isOpen())
31 m_outputTarget->
close();
33 if (!m_mediaRecorder.isNull()) {
34 m_mediaStreamDataAvailable.
reset(
nullptr);
35 m_mediaStreamStopped.
reset(
nullptr);
36 m_mediaStreamError.
reset(
nullptr);
37 m_mediaStreamStart.
reset(
nullptr);
50 if (!m_mediaRecorder.isUndefined()) {
51 std::string
state = m_mediaRecorder[
"state"].as<std::string>();
52 if (
state ==
"recording")
54 else if (
state ==
"paused")
57 return recordingState;
76 if (!m_session || (m_mediaRecorder.isUndefined() || m_mediaRecorder.isNull())) {
80 m_mediaRecorder.call<
void>(
"pause");
86 if (!m_session || (m_mediaRecorder.isUndefined() || m_mediaRecorder.isNull())) {
91 m_mediaRecorder.call<
void>(
"resume");
97 if (!m_session || (m_mediaRecorder.isUndefined() || m_mediaRecorder.isNull())) {
101 if (m_mediaRecorder[
"state"].as<std::string>() ==
"recording")
102 m_mediaRecorder.call<
void>(
"stop");
110bool QWasmMediaRecorder::hasCamera()
const
112 return m_session && m_session->
camera();
115void QWasmMediaRecorder::initUserMedia()
118 emscripten::val navigator = emscripten::val::global(
"navigator");
119 emscripten::val mediaDevices = navigator[
"mediaDevices"];
121 if (mediaDevices.isNull() || mediaDevices.isUndefined()) {
122 qCDebug(qWasmMediaRecorder) <<
"MediaDevices are undefined or null";
130 emscripten::val
stream = emscripten::val::undefined();
137 if (m_video.isNull() || m_video.isUndefined()) {
142 stream = m_video[
"srcObject"];
165void QWasmMediaRecorder::startAudioRecording()
170void QWasmMediaRecorder::setStream(emscripten::val
stream)
172 emscripten::val emMediaSettings = emscripten::val::object();
192 emMediaSettings.set(
"mimeType", mimeCodec.toStdString());
196 emMediaSettings.set(
"audioBitsPerSecond", emscripten::val(m_mediaSettings.
audioBitRate()));
199 emMediaSettings.set(
"videoBitsPerSecond", emscripten::val(m_mediaSettings.
videoBitRate()));
202 m_mediaRecorder = emscripten::val::global(
"MediaRecorder").new_(
stream, emMediaSettings);
207 if (m_mediaRecorder.isNull() || m_mediaRecorder.isUndefined()) {
208 qWarning() <<
"MediaRecorder could not be found";
211 m_mediaRecorder.set(
"data-mediarecordercontext",
212 emscripten::val(
quintptr(
reinterpret_cast<void *
>(
this))));
214 if (!m_mediaStreamDataAvailable.
isNull()) {
215 m_mediaStreamDataAvailable.
reset();
216 m_mediaStreamStopped.
reset();
217 m_mediaStreamError.
reset();
218 m_mediaStreamStart.
reset();
219 m_mediaStreamPause.
reset();
220 m_mediaStreamResume.
reset();
224 auto callback = [](emscripten::val blob) {
225 if (blob.isUndefined() || blob.isNull()) {
226 qCDebug(qWasmMediaRecorder) <<
"blob is null";
229 if (blob[
"target"].isUndefined() || blob[
"target"].
isNull())
231 if (blob[
"data"].isUndefined() || blob[
"data"].
isNull())
233 if (blob[
"target"][
"data-mediarecordercontext"].isUndefined()
234 || blob[
"target"][
"data-mediarecordercontext"].
isNull())
238 blob[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
241 const double timeCode =
242 blob.hasOwnProperty(
"timecode") ? blob[
"timecode"].as<
double>() : 0;
243 recorder->audioDataAvailable(blob[
"data"], timeCode);
247 m_mediaStreamDataAvailable.
reset(
251 auto stoppedCallback = [](emscripten::val
event) {
252 if (
event.isUndefined() ||
event.isNull()) {
253 qCDebug(qWasmMediaRecorder) <<
"event is null";
257 <<
"STOPPED: state changed"
261 event[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
265 recorder->m_durationTimer->invalidate();
271 m_mediaStreamStopped.
reset(
275 auto errorCallback = [](emscripten::val theError) {
276 if (theError.isUndefined() || theError.isNull()) {
277 qCDebug(qWasmMediaRecorder) <<
"error is null";
281 << theError[
"code"].as<
int>()
285 theError[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
297 auto startCallback = [](emscripten::val
event) {
298 if (
event.isUndefined() ||
event.isNull()) {
299 qCDebug(qWasmMediaRecorder) <<
"event is null";
304 <<
"START: state changed"
308 event[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
320 auto pauseCallback = [](emscripten::val
event) {
321 if (
event.isUndefined() ||
event.isNull()) {
322 qCDebug(qWasmMediaRecorder) <<
"event is null";
327 <<
"pause: state changed"
331 event[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
343 auto resumeCallback = [](emscripten::val
event) {
344 if (
event.isUndefined() ||
event.isNull()) {
345 qCDebug(qWasmMediaRecorder) <<
"event is null";
350 <<
"resume: state changed"
354 event[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
363 m_mediaStreamResume.
reset(
368 setTrackContraints(m_mediaSettings,
stream);
373void QWasmMediaRecorder::audioDataAvailable(emscripten::val blob,
double timeCodeDifference)
376 if (blob.isUndefined() || blob.isNull()) {
377 qCDebug(qWasmMediaRecorder) <<
"blob is null";
381 auto fileReader = std::make_shared<qstdweb::FileReader>();
383 fileReader->
onError([=](emscripten::val theError) {
388 fileReader->
onAbort([=](emscripten::val) {
392 fileReader->
onLoad([=](emscripten::val) {
393 if (fileReader->
val().isNull() || fileReader->
val().isUndefined())
396 if (
result.val().isNull() ||
result.val().isUndefined())
400 if (m_isRecording && !fileContent.isEmpty()) {
401 m_durationMs = m_durationTimer->
elapsed();
402 if (m_outputTarget->
isOpen())
403 m_outputTarget->
write(fileContent, fileContent.length());
406 qCDebug(qWasmMediaRecorder) <<
"duration changed" << m_durationMs;
423 emscripten::val navigator = emscripten::val::global(
"navigator");
424 emscripten::val mediaDevices = navigator[
"mediaDevices"];
430 emscripten::val videoParams = emscripten::val::object();
431 emscripten::val constraints = emscripten::val::object();
435 videoParams.set(
"frameRate", emscripten::val(
settings.videoFrameRate()));
436 if (
settings.videoResolution().height() > 0)
437 videoParams.set(
"height",
438 emscripten::val(
settings.videoResolution().height()));
439 if (
settings.videoResolution().width() > 0)
440 videoParams.set(
"width", emscripten::val(
settings.videoResolution().width()));
442 constraints.set(
"video", videoParams);
445 emscripten::val audioParams = emscripten::val::object();
447 audioParams.set(
"sampleRate", emscripten::val(
settings.audioSampleRate()));
449 audioParams.set(
"sampleSize", emscripten::val(
settings.audioBitRate()));
450 if (
settings.audioChannelCount() > 0)
451 audioParams.set(
"channelCount", emscripten::val(
settings.audioChannelCount()));
453 constraints.set(
"audio", audioParams);
455 if (hasCamera() &&
stream[
"active"].as<bool>()) {
456 emscripten::val videoTracks = emscripten::val::undefined();
457 videoTracks =
stream.call<emscripten::val>(
"getVideoTracks");
458 if (videoTracks.isNull() || videoTracks.isUndefined()) {
459 qCDebug(qWasmMediaRecorder) <<
"no video tracks";
462 if (videoTracks[
"length"].as<int>() > 0) {
466 [
this](emscripten::val
result) {
471 [
this](emscripten::val theError) {
472 qWarning() <<
"setting video params failed error";
474 << theError[
"code"].as<
int>()
485void QWasmMediaRecorder::startStream()
487 if (m_mediaRecorder.isUndefined() || m_mediaRecorder.isNull()) {
491 qCDebug(qWasmMediaRecorder) <<
"m_mediaRecorder state:" <<
494 constexpr int sliceSizeInMs = 250;
495 m_mediaRecorder.call<
void>(
"start", emscripten::val(sliceSizeInMs));
504void QWasmMediaRecorder::setUpFileSink()
508 if (m_targetFileName.isEmpty()) {
509 m_targetFileName =
"/home/web_user/tmp." + suffix;
513 m_outputTarget =
new QFile(m_targetFileName,
this);
515 qWarning() <<
"target file is not writable";
AVFCameraSession * m_session
AVCaptureDeviceInput * audioInput() const
qint64 elapsed() const noexcept
Returns the number of milliseconds since this QElapsedTimer was last started.
virtual bool open(QIODeviceBase::OpenMode mode)
Opens the device and sets its OpenMode to mode.
bool isOpen() const
Returns true if the device is open; otherwise returns false.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
virtual void close()
First emits aboutToClose(), then closes the device and sets its OpenMode to NotOpen.
QString preferredSuffix
the preferred suffix for the MIME type
QString name
the name of the MIME type
bool isNull() const noexcept
Returns true if this object refers to \nullptr.
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString fromStdString(const std::string &s)
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
QString toLocalFile() const
Returns the path of this URL formatted as a local file path.
QWasmVideoOutput * cameraOutput()
emscripten::val surfaceElement()
void onAbort(const std::function< void(emscripten::val)> &onAbort)
ArrayBuffer result() const
void onLoad(const std::function< void(emscripten::val)> &onLoad)
void readAsArrayBuffer(const Blob &blob) const
void onError(const std::function< void(emscripten::val)> &onError)
emscripten::val val() const
QByteArray copyToQByteArray() const
Combined button and popup list for selecting options.
void make(emscripten::val target, QString methodName, PromiseCallbacks callbacks, Args... args)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define QStringLiteral(str)
QSettings settings("MySoft", "Star Runner")
[0]