blob: e90199a46eaa1655db058967608a45e484b1fa88 [file] [log] [blame]
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/media_capture/media_devices.h"
#include <string>
#include "cobalt/dom/dom_exception.h"
#include "cobalt/media_capture/media_device_info.h"
#include "cobalt/media_stream/media_stream.h"
#include "cobalt/speech/microphone.h"
#include "cobalt/speech/microphone_fake.h"
#include "cobalt/speech/microphone_starboard.h"
#include "starboard/string.h"
namespace cobalt {
namespace media_capture {
#if SB_USE_SB_MICROPHONE && !defined(DISABLE_MICROPHONE_IDL)
#define ENABLE_MICROPHONE_IDL
#endif
namespace {
using speech::Microphone;
scoped_ptr<Microphone> CreateMicrophone(const Microphone::Options& options) {
#if defined(ENABLE_FAKE_MICROPHONE)
if (options.enable_fake_microphone) {
return make_scoped_ptr<speech::Microphone>(
new speech::MicrophoneFake(options));
}
#else
UNREFERENCED_PARAMETER(options);
#endif // defined(ENABLE_FAKE_MICROPHONE)
scoped_ptr<Microphone> mic;
#if defined(ENABLE_MICROPHONE_IDL)
mic.reset(new speech::MicrophoneStarboard(
speech::MicrophoneStarboard::kDefaultSampleRate,
/* Buffer for one second. */
speech::MicrophoneStarboard::kDefaultSampleRate *
speech::MicrophoneStarboard::kSbMicrophoneSampleSizeInBytes));
#endif // defined(ENABLE_MICROPHONE_IDL)
return mic.Pass();
}
} // namespace.
MediaDevices::MediaDevices(script::ScriptValueFactory* script_value_factory)
: script_value_factory_(script_value_factory) {
}
script::Handle<MediaDevices::MediaInfoSequencePromise>
MediaDevices::EnumerateDevices() {
DCHECK(settings_);
DCHECK(script_value_factory_);
script::Handle<MediaInfoSequencePromise> promise =
script_value_factory_->CreateBasicPromise<MediaInfoSequence>();
script::Sequence<scoped_refptr<Wrappable>> output;
scoped_ptr<speech::Microphone> microphone =
CreateMicrophone(settings_->microphone_options());
if (microphone) {
scoped_refptr<Wrappable> media_device(
new MediaDeviceInfo(script_value_factory_, kMediaDeviceKindAudioinput,
microphone->Label()));
output.push_back(media_device);
}
promise->Resolve(output);
return promise;
}
script::Handle<MediaDevices::MediaStreamPromise> MediaDevices::GetUserMedia() {
DCHECK(script_value_factory_);
script::Handle<MediaDevices::MediaStreamPromise> promise =
script_value_factory_->CreateInterfacePromise<
script::ScriptValueFactory::WrappablePromise>();
// Per specification at
// https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia
//
// Step 3: If requestedMediaTypes is the empty set, return a promise rejected
// with a TypeError. The word "optional" occurs in the WebIDL due to WebIDL
// rules, but the argument must be supplied in order for the call to succeed.
promise->Reject(script::kTypeError);
return promise;
}
script::Handle<MediaDevices::MediaStreamPromise> MediaDevices::GetUserMedia(
const media_stream::MediaStreamConstraints& constraints) {
script::Handle<MediaDevices::MediaStreamPromise> promise =
script_value_factory_->CreateInterfacePromise<
script::ScriptValueFactory::WrappablePromise>();
if (!constraints.audio()) {
// Step 3: If requestedMediaTypes is the empty set, return a promise
// rejected with a TypeError. The word "optional" occurs in the WebIDL due
// to WebIDL rules, but the argument must be supplied in order for the call
// to succeed.
DLOG(INFO) << "Audio constraint must be true.";
promise->Reject(script::kTypeError);
return promise;
}
// Steps 4-7 are not needed for cobalt.
// Step 8 is to create a promise (which is already done).
// Step 9: Construct a list of MediaStreamTracks that we have permission.
CreateMicrophoneIfNeeded();
if (!microphone_) {
promise->Reject(new dom::DOMException(dom::DOMException::kNotFoundErr));
return promise;
}
bool open_success = microphone_->Open();
if (!open_success) {
// This typically happens if the user did not give permission.
// Step 9.8, handle "Permission Failure"
DLOG(INFO) << "Unable to open the microphone.";
promise->Reject(new dom::DOMException(dom::DOMException::kNotAllowedErr));
}
using media_stream::MediaStream;
scoped_refptr<media_stream::MediaStreamTrack> microphone_track;
// TODO: Attach a microphone device to the microphone track.
MediaStream::TrackSequences audio_tracks;
audio_tracks.push_back(microphone_track);
auto media_stream(make_scoped_refptr(new MediaStream(audio_tracks)));
promise->Resolve(media_stream);
// Step 10, return promise.
return promise;
}
void MediaDevices::CreateMicrophoneIfNeeded() {
DCHECK(settings_);
if (microphone_) {
return;
}
scoped_ptr<speech::Microphone> microphone =
CreateMicrophone(settings_->microphone_options());
if (!microphone) {
DLOG(INFO) << "Unable to create a microphone.";
return;
}
if (!microphone->IsValid()) {
DLOG(INFO) << "Ignoring created microphone because it is invalid.";
return;
}
DLOG(INFO) << "Created microphone: " << microphone->Label();
microphone_ = microphone.Pass();
}
} // namespace media_capture
} // namespace cobalt