Skip to content
This repository has been archived by the owner on Jan 19, 2022. It is now read-only.

Commit

Permalink
Use nsRunnable to dipatch JS callback. Closes #8
Browse files Browse the repository at this point in the history
  • Loading branch information
anantn committed Mar 16, 2011
1 parent f94e5e8 commit baedca0
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 24 deletions.
74 changes: 58 additions & 16 deletions components/MediaRecorder.cpp
Expand Up @@ -55,6 +55,25 @@ MediaRecorder::GetSingleton()
return gMediaRecordingService;
}

/*
* Special runnable object to dispatch JS callback on main thread
*/
class MediaCallback : public nsRunnable {
public:
MediaCallback(nsIMediaStateObserver *obs, const char *msg, const char *arg) {
m_Obs = obs;
strcpy(m_Msg, msg);
strcpy(m_Arg, arg);
}

NS_IMETHOD Run() {
return m_Obs->OnStateChange((char *)m_Msg, (char *)m_Arg);
}

private:
nsIMediaStateObserver *m_Obs;
char m_Msg[128]; char m_Arg[256];
};

/*
* === Here's the meat of the code. Static callbacks & encoder ===
Expand Down Expand Up @@ -543,14 +562,14 @@ MediaRecorder::RecordToFile(
{
nsresult rv;
ParseProperties(prop);

/* Get a file stream from the local file */

canvas = ctx;
observer = obs;

/* Get a file stream from the local file */
nsCOMPtr<nsIFileOutputStream> stream(
do_CreateInstance("@mozilla.org/network/file-output-stream;1")
);

pipeStream = do_QueryInterface(stream, &rv);
if (NS_FAILED(rv)) return rv;
rv = stream->Init(file, -1, -1, 0);
Expand Down Expand Up @@ -578,7 +597,9 @@ MediaRecorder::Record(void *data)
Properties *params = mr->params;

if (mr->a_rec || mr->v_rec) {
mr->observer->OnStateChange("error", "recording already in progress");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "error", "recording already in progress"
));
return;
}

Expand Down Expand Up @@ -610,11 +631,15 @@ MediaRecorder::Record(void *data)

/* FIXME: device detection TBD */
if (params->audio && (mr->aState == nsnull)) {
mr->observer->OnStateChange("error", "audio requested but no devices found");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "error", "audio requested but no devices found"
));
return;
}
if (params->video && (mr->vState == nsnull)) {
mr->observer->OnStateChange("error", "video requested but no devices found");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "error", "video requested but no devices found"
));
return;
}

Expand All @@ -626,7 +651,9 @@ MediaRecorder::Record(void *data)
getter_AddRefs(mr->vState->vPipeOut)
);
if (NS_FAILED(rv)) {
mr->observer->OnStateChange("error", "internal: could not create video pipe");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "error", "internal: could not create video pipe"
));
return;
}
}
Expand All @@ -639,7 +666,9 @@ MediaRecorder::Record(void *data)
getter_AddRefs(mr->aState->aPipeOut)
);
if (NS_FAILED(rv)) {
mr->observer->OnStateChange("error", "internal: could not create audio pipe");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "error", "internal: could not create audio pipe"
));
return;
}
}
Expand All @@ -649,7 +678,9 @@ MediaRecorder::Record(void *data)
mr->SetupTheoraHeaders();
rv = mr->vState->backend->Start(mr->vState->vPipeOut, mr->canvas);
if (NS_FAILED(rv)) {
mr->observer->OnStateChange("error", "internal: could not start video recording");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "error", "internal: could not start video recording"
));
return;
}
mr->v_rec = PR_TRUE;
Expand All @@ -660,15 +691,19 @@ MediaRecorder::Record(void *data)
rv = mr->aState->backend->Start(mr->aState->aPipeOut);
if (NS_FAILED(rv)) {
/* FIXME: Stop and clean up video! */
mr->observer->OnStateChange("error", "internal: could not start video recording");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "error", "internal: could not start audio recording"
));
return;
}
mr->a_rec = PR_TRUE;
mr->a_stp = PR_FALSE;
}

/* Start off encoder after notifying observer */
mr->observer->OnStateChange("started", "");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "started", ""
));
mr->Encode(data);
return;
}
Expand All @@ -680,7 +715,9 @@ NS_IMETHODIMP
MediaRecorder::Stop()
{
if (!a_rec && !v_rec) {
observer->OnStateChange("error", "no recording in progress");
NS_DispatchToMainThread(new MediaCallback(
observer, "error", "no recording in progress"
));
return NS_ERROR_FAILURE;
}

Expand All @@ -707,15 +744,19 @@ MediaRecorder::StopRecord(void *data)
if (mr->v_rec) {
rv = mr->vState->backend->Stop();
if (NS_FAILED(rv)) {
mr->observer->OnStateChange("error", "could not stop video recording");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "error", "could not stop video recording"
));
return;
}
}

if (mr->a_rec) {
rv = mr->aState->backend->Stop();
if (NS_FAILED(rv)) {
mr->observer->OnStateChange("error", "could not stop audio recording");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "error", "could not stop audio recording"
));
return;
}
}
Expand Down Expand Up @@ -767,7 +808,8 @@ MediaRecorder::StopRecord(void *data)

/* GG */
mr->pipeStream->Close();
mr->observer->OnStateChange("stopped", "");
NS_DispatchToMainThread(new MediaCallback(
mr->observer, "stopped", ""
));
return;
}

11 changes: 5 additions & 6 deletions components/MediaRecorder.h
Expand Up @@ -47,17 +47,17 @@
#include <plbase64.h>
#include <prthread.h>

#include <nsCOMPtr.h>
#include <nsAutoPtr.h>
#include <nsStringAPI.h>

#include <nsIPipe.h>
#include <nsIFileStreams.h>
#include <nsIAsyncInputStream.h>
#include <nsIAsyncOutputStream.h>
#include <nsComponentManagerUtils.h>
#include <nsIDOMCanvasRenderingContext2D.h>

#include <nsCOMPtr.h>
#include <nsAutoPtr.h>
#include <nsStringAPI.h>
#include <nsComponentManagerUtils.h>

/* ifdefs are evil, but I am powerless. This is better than factory classes! */
#ifdef RAINBOW_Mac
#include "VideoSourceMac.h"
Expand Down Expand Up @@ -158,7 +158,6 @@ class MediaRecorder : public IMediaRecorder

private:
Properties *params;

};

#endif
14 changes: 12 additions & 2 deletions content/example.html
Expand Up @@ -27,7 +27,17 @@ <h1>Recording Example</h1>
}

function onStateChange(type, arg) {
msg.innerHTML = type + " :: " + arg;
switch (type) {
case "started":
msg.innerHTML = "Recording has begun!";
break;
case "stopped":
// Recording stopped, message is displayed by onclick code
break;
case "error":
msg.innerHTML = "There was an error :( " + type + " :: " + arg;
break;
}
}

but.onclick = function() {
Expand All @@ -46,7 +56,7 @@ <h1>Recording Example</h1>
// Start recording
Re = true;
but.value = "Stop!";
msg.innerHTML = " ";
msg.innerHTML = "Loading...";
Sr = Me.recordToFile({}, ctx, onStateChange);
}
}
Expand Down

0 comments on commit baedca0

Please sign in to comment.