6#include <private/qplatformmediadevices_p.h>
10#include <private/qstdweb_p.h>
11#include <QtCore/QIODevice>
29 if (m_outputTarget->
isOpen())
30 m_outputTarget->
close();
32 if (!m_mediaRecorder.isNull()) {
33 m_mediaStreamDataAvailable.
reset(
nullptr);
34 m_mediaStreamStopped.
reset(
nullptr);
35 m_mediaStreamError.
reset(
nullptr);
36 m_mediaStreamStart.
reset(
nullptr);
49 if (!m_mediaRecorder.isUndefined()) {
50 std::string
state = m_mediaRecorder[
"state"].as<std::string>();
51 if (
state ==
"recording")
53 else if (
state ==
"paused")
56 return recordingState;
75 if (!m_session || (m_mediaRecorder.isUndefined() || m_mediaRecorder.isNull())) {
79 m_mediaRecorder.call<
void>(
"pause");
85 if (!m_session || (m_mediaRecorder.isUndefined() || m_mediaRecorder.isNull())) {
90 m_mediaRecorder.call<
void>(
"resume");
96 if (!m_session || (m_mediaRecorder.isUndefined() || m_mediaRecorder.isNull())) {
100 if (m_mediaRecorder[
"state"].as<std::string>() ==
"recording")
101 m_mediaRecorder.call<
void>(
"stop");
109bool QWasmMediaRecorder::hasCamera()
const
111 return m_session && m_session->
camera();
114void QWasmMediaRecorder::initUserMedia()
117 emscripten::val navigator = emscripten::val::global(
"navigator");
118 emscripten::val mediaDevices = navigator[
"mediaDevices"];
120 if (mediaDevices.isNull() || mediaDevices.isUndefined()) {
121 qCDebug(qWasmMediaRecorder) <<
"MediaDevices are undefined or null";
129 emscripten::val
stream = emscripten::val::undefined();
136 if (m_video.isNull() || m_video.isUndefined()) {
141 stream = m_video[
"srcObject"];
164void QWasmMediaRecorder::startAudioRecording()
169void QWasmMediaRecorder::setStream(emscripten::val
stream)
171 emscripten::val emMediaSettings = emscripten::val::object();
191 emMediaSettings.set(
"mimeType", mimeCodec.
toStdString());
195 emMediaSettings.set(
"audioBitsPerSecond", emscripten::val(m_mediaSettings.
audioBitRate()));
198 emMediaSettings.set(
"videoBitsPerSecond", emscripten::val(m_mediaSettings.
videoBitRate()));
201 m_mediaRecorder = emscripten::val::global(
"MediaRecorder").new_(
stream, emMediaSettings);
206 if (m_mediaRecorder.isNull() || m_mediaRecorder.isUndefined()) {
207 qWarning() <<
"MediaRecorder could not be found";
210 m_mediaRecorder.set(
"data-mediarecordercontext",
211 emscripten::val(
quintptr(
reinterpret_cast<void *
>(
this))));
213 if (!m_mediaStreamDataAvailable.
isNull()) {
214 m_mediaStreamDataAvailable.
reset();
215 m_mediaStreamStopped.
reset();
216 m_mediaStreamError.
reset();
217 m_mediaStreamStart.
reset();
218 m_mediaStreamPause.
reset();
219 m_mediaStreamResume.
reset();
223 auto callback = [](emscripten::val blob) {
224 if (blob.isUndefined() || blob.isNull()) {
225 qCDebug(qWasmMediaRecorder) <<
"blob is null";
228 if (blob[
"target"].isUndefined() || blob[
"target"].
isNull())
230 if (blob[
"data"].isUndefined() || blob[
"data"].
isNull())
232 if (blob[
"target"][
"data-mediarecordercontext"].isUndefined()
233 || blob[
"target"][
"data-mediarecordercontext"].
isNull())
237 blob[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
240 const double timeCode =
241 blob.hasOwnProperty(
"timecode") ? blob[
"timecode"].as<
double>() : 0;
242 recorder->audioDataAvailable(blob[
"data"], timeCode);
246 m_mediaStreamDataAvailable.
reset(
250 auto stoppedCallback = [](emscripten::val
event) {
251 if (
event.isUndefined() ||
event.isNull()) {
252 qCDebug(qWasmMediaRecorder) <<
"event is null";
256 <<
"STOPPED: state changed"
260 event[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
264 recorder->m_durationTimer->invalidate();
270 m_mediaStreamStopped.
reset(
274 auto errorCallback = [](emscripten::val theError) {
275 if (theError.isUndefined() || theError.isNull()) {
276 qCDebug(qWasmMediaRecorder) <<
"error is null";
280 << theError[
"code"].as<
int>()
284 theError[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
296 auto startCallback = [](emscripten::val
event) {
297 if (
event.isUndefined() ||
event.isNull()) {
298 qCDebug(qWasmMediaRecorder) <<
"event is null";
303 <<
"START: state changed"
307 event[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
319 auto pauseCallback = [](emscripten::val
event) {
320 if (
event.isUndefined() ||
event.isNull()) {
321 qCDebug(qWasmMediaRecorder) <<
"event is null";
326 <<
"pause: state changed"
330 event[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
342 auto resumeCallback = [](emscripten::val
event) {
343 if (
event.isUndefined() ||
event.isNull()) {
344 qCDebug(qWasmMediaRecorder) <<
"event is null";
349 <<
"resume: state changed"
353 event[
"target"][
"data-mediarecordercontext"].as<
quintptr>());
362 m_mediaStreamResume.
reset(
367 setTrackContraints(m_mediaSettings,
stream);
372void QWasmMediaRecorder::audioDataAvailable(emscripten::val blob,
double timeCodeDifference)
375 if (blob.isUndefined() || blob.isNull()) {
376 qCDebug(qWasmMediaRecorder) <<
"blob is null";
380 auto fileReader = std::make_shared<qstdweb::FileReader>();
382 fileReader->
onError([=](emscripten::val theError) {
387 fileReader->
onAbort([=](emscripten::val) {
391 fileReader->
onLoad([=](emscripten::val) {
392 if (fileReader->
val().isNull() || fileReader->
val().isUndefined())
395 if (
result.val().isNull() ||
result.val().isUndefined())
399 if (m_isRecording && !fileContent.
isEmpty()) {
400 m_durationMs = m_durationTimer->
elapsed();
401 if (m_outputTarget->
isOpen())
402 m_outputTarget->
write(fileContent, fileContent.
length());
405 qCDebug(qWasmMediaRecorder) <<
"duration changed" << m_durationMs;
422 emscripten::val navigator = emscripten::val::global(
"navigator");
423 emscripten::val mediaDevices = navigator[
"mediaDevices"];
429 emscripten::val videoParams = emscripten::val::object();
430 emscripten::val constraints = emscripten::val::object();
434 videoParams.set(
"frameRate", emscripten::val(
settings.videoFrameRate()));
435 if (
settings.videoResolution().height() > 0)
436 videoParams.set(
"height",
437 emscripten::val(
settings.videoResolution().height()));
438 if (
settings.videoResolution().width() > 0)
439 videoParams.set(
"width", emscripten::val(
settings.videoResolution().width()));
441 constraints.set(
"video", videoParams);
444 emscripten::val audioParams = emscripten::val::object();
446 audioParams.set(
"sampleRate", emscripten::val(
settings.audioSampleRate()));
448 audioParams.set(
"sampleSize", emscripten::val(
settings.audioBitRate()));
449 if (
settings.audioChannelCount() > 0)
450 audioParams.set(
"channelCount", emscripten::val(
settings.audioChannelCount()));
452 constraints.set(
"audio", audioParams);
454 if (hasCamera() &&
stream[
"active"].as<bool>()) {
455 emscripten::val videoTracks = emscripten::val::undefined();
456 videoTracks =
stream.call<emscripten::val>(
"getVideoTracks");
457 if (videoTracks.isNull() || videoTracks.isUndefined()) {
458 qCDebug(qWasmMediaRecorder) <<
"no video tracks";
461 if (videoTracks[
"length"].as<int>() > 0) {
465 [
this](emscripten::val
result) {
470 [
this](emscripten::val theError) {
471 qWarning() <<
"setting video params failed error";
473 << theError[
"code"].as<
int>()
483void QWasmMediaRecorder::startStream()
485 if (m_mediaRecorder.isUndefined() || m_mediaRecorder.isNull()) {
489 qCDebug(qWasmMediaRecorder) <<
"m_mediaRecorder state:" <<
492 constexpr int sliceSizeInMs = 250;
493 m_mediaRecorder.call<
void>(
"start", emscripten::val(sliceSizeInMs));
502void QWasmMediaRecorder::setUpFileSink()
506 if (m_targetFileName.
isEmpty()) {
507 m_targetFileName =
"/home/web_user/tmp." + suffix;
511 m_outputTarget =
new QFile(m_targetFileName,
this);
513 qWarning() <<
"target file is not writable";
AVFCameraSession * m_session
AVCaptureDeviceInput * audioInput() const
qsizetype length() const noexcept
Same as size().
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
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)
std::string toStdString() const
Returns a std::string object with the data contained in this QString.
bool isEmpty() const
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)
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]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent