зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1221587: use cubeb devids to select input devices r=padenot
--HG-- extra : commitid : AH6Lt4KfNaF
This commit is contained in:
Родитель
be7d8f1d36
Коммит
46878bf96f
|
@ -13,6 +13,8 @@
|
|||
namespace mozilla {
|
||||
namespace CubebUtils {
|
||||
|
||||
typedef cubeb_devid AudioDeviceID;
|
||||
|
||||
// Initialize Audio Library. Some Audio backends require initializing the
|
||||
// library before using it.
|
||||
void InitLibrary();
|
||||
|
|
|
@ -559,23 +559,23 @@ AudioCallbackDriver::~AudioCallbackDriver()
|
|||
void
|
||||
AudioCallbackDriver::Init()
|
||||
{
|
||||
cubeb_stream_params out_params;
|
||||
cubeb_stream_params in_params;
|
||||
cubeb_stream_params output;
|
||||
cubeb_stream_params input;
|
||||
uint32_t latency;
|
||||
|
||||
MOZ_ASSERT(!NS_IsMainThread(),
|
||||
"This is blocking and should never run on the main thread.");
|
||||
|
||||
out_params.devid = nullptr; // XXX take from config for the graph
|
||||
mSampleRate = out_params.rate = CubebUtils::PreferredSampleRate();
|
||||
output.devid = mGraphImpl->mOutputDeviceID;
|
||||
mSampleRate = output.rate = CubebUtils::PreferredSampleRate();
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#if defined(MOZ_B2G)
|
||||
out_params.stream_type = CubebUtils::ConvertChannelToCubebType(mAudioChannel);
|
||||
output.stream_type = CubebUtils::ConvertChannelToCubebType(mAudioChannel);
|
||||
#else
|
||||
out_params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
|
||||
output.stream_type = CUBEB_STREAM_TYPE_MUSIC;
|
||||
#endif
|
||||
if (out_params.stream_type == CUBEB_STREAM_TYPE_MAX) {
|
||||
if (output.stream_type == CUBEB_STREAM_TYPE_MAX) {
|
||||
NS_WARNING("Bad stream type");
|
||||
return;
|
||||
}
|
||||
|
@ -583,27 +583,30 @@ AudioCallbackDriver::Init()
|
|||
(void)mAudioChannel;
|
||||
#endif
|
||||
|
||||
out_params.channels = mGraphImpl->AudioChannelCount();
|
||||
output.channels = mGraphImpl->AudioChannelCount();
|
||||
if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
|
||||
out_params.format = CUBEB_SAMPLE_S16NE;
|
||||
output.format = CUBEB_SAMPLE_S16NE;
|
||||
} else {
|
||||
out_params.format = CUBEB_SAMPLE_FLOAT32NE;
|
||||
output.format = CUBEB_SAMPLE_FLOAT32NE;
|
||||
}
|
||||
|
||||
if (cubeb_get_min_latency(CubebUtils::GetCubebContext(), out_params, &latency) != CUBEB_OK) {
|
||||
if (cubeb_get_min_latency(CubebUtils::GetCubebContext(), output, &latency) != CUBEB_OK) {
|
||||
NS_WARNING("Could not get minimal latency from cubeb.");
|
||||
return;
|
||||
}
|
||||
|
||||
in_params = out_params;
|
||||
in_params.channels = 1; // change to support optional stereo capture
|
||||
input = output;
|
||||
input.channels = 1; // change to support optional stereo capture
|
||||
input.devid = mGraphImpl->mInputDeviceID;
|
||||
|
||||
cubeb_stream* stream;
|
||||
// XXX Only pass input in_params if we have an input listener. Always
|
||||
// XXX Only pass input input if we have an input listener. Always
|
||||
// set up output because it's easier, and it will just get silence.
|
||||
// XXX Add support for adding/removing an input listener later.
|
||||
if (cubeb_stream_init(CubebUtils::GetCubebContext(), &stream,
|
||||
"AudioCallbackDriver", &out_params, &in_params, latency,
|
||||
"AudioCallbackDriver",
|
||||
mGraphImpl->mInputWanted ? &input : nullptr,
|
||||
mGraphImpl->mOutputWanted ? &output : nullptr, latency,
|
||||
DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
|
||||
mAudioStream.own(stream);
|
||||
} else {
|
||||
|
|
|
@ -924,8 +924,13 @@ MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
|||
}
|
||||
|
||||
void
|
||||
MediaStreamGraphImpl::OpenAudioInputImpl(char *aName, AudioDataListener *aListener)
|
||||
MediaStreamGraphImpl::OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
|
||||
AudioDataListener *aListener)
|
||||
{
|
||||
MOZ_ASSERT(!mInputWanted);
|
||||
mInputWanted = true;
|
||||
mInputDeviceID = aID;
|
||||
// XXX Switch Drivers
|
||||
if (CurrentDriver()->AsAudioCallbackDriver()) {
|
||||
CurrentDriver()->SetInputListener(aListener);
|
||||
} else {
|
||||
|
@ -935,35 +940,40 @@ MediaStreamGraphImpl::OpenAudioInputImpl(char *aName, AudioDataListener *aListen
|
|||
}
|
||||
|
||||
nsresult
|
||||
MediaStreamGraphImpl::OpenAudioInput(char *aName, AudioDataListener *aListener)
|
||||
MediaStreamGraphImpl::OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
||||
AudioDataListener *aListener)
|
||||
{
|
||||
// XXX So, so, so annoying. Can't AppendMessage except on Mainthread
|
||||
if (!NS_IsMainThread()) {
|
||||
NS_DispatchToMainThread(WrapRunnable(this,
|
||||
&MediaStreamGraphImpl::OpenAudioInput,
|
||||
aName, aListener)); // XXX Fix! string need to copied
|
||||
aID, aListener)); // XXX Fix! string need to copied
|
||||
return NS_OK;
|
||||
}
|
||||
class Message : public ControlMessage {
|
||||
public:
|
||||
Message(MediaStreamGraphImpl *aGraph, char *aName, AudioDataListener *aListener) :
|
||||
ControlMessage(nullptr), mGraph(aGraph), mName(aName), mListener(aListener) {}
|
||||
Message(MediaStreamGraphImpl *aGraph, CubebUtils::AudioDeviceID aID,
|
||||
AudioDataListener *aListener) :
|
||||
ControlMessage(nullptr), mGraph(aGraph), mID(aID), mListener(aListener) {}
|
||||
virtual void Run()
|
||||
{
|
||||
mGraph->OpenAudioInputImpl(mName, mListener);
|
||||
mGraph->OpenAudioInputImpl(mID, mListener);
|
||||
}
|
||||
MediaStreamGraphImpl *mGraph;
|
||||
char *mName; // XXX needs to copy
|
||||
CubebUtils::AudioDeviceID mID;
|
||||
RefPtr<AudioDataListener> mListener;
|
||||
};
|
||||
this->AppendMessage(new Message(this, aName, aListener));
|
||||
this->AppendMessage(new Message(this, aID, aListener));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaStreamGraphImpl::CloseAudioInputImpl(AudioDataListener *aListener)
|
||||
{
|
||||
mInputDeviceID = nullptr;
|
||||
mInputWanted = false;
|
||||
CurrentDriver()->RemoveInputListener(aListener);
|
||||
// XXX Switch Drivers
|
||||
mAudioInputs.RemoveElement(aListener);
|
||||
}
|
||||
|
||||
|
@ -2711,6 +2721,10 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
|
|||
dom::AudioChannel aChannel)
|
||||
: MediaStreamGraph(aSampleRate)
|
||||
, mPortCount(0)
|
||||
, mInputWanted(false)
|
||||
, mInputDeviceID(nullptr)
|
||||
, mOutputWanted(true)
|
||||
, mOutputDeviceID(nullptr)
|
||||
, mNeedAnotherIteration(false)
|
||||
, mGraphDriverAsleep(false)
|
||||
, mMonitor("MediaStreamGraphImpl")
|
||||
|
|
|
@ -1208,7 +1208,8 @@ public:
|
|||
// Idempotent
|
||||
static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
|
||||
|
||||
virtual nsresult OpenAudioInput(char *aName, AudioDataListener *aListener) {
|
||||
virtual nsresult OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
||||
AudioDataListener *aListener) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
virtual void CloseAudioInput(AudioDataListener *aListener) {}
|
||||
|
|
|
@ -350,8 +350,10 @@ public:
|
|||
* at the current buffer end point. The StreamBuffer's tracks must be
|
||||
* explicitly set to finished by the caller.
|
||||
*/
|
||||
void OpenAudioInputImpl(char *aName, AudioDataListener *aListener);
|
||||
virtual nsresult OpenAudioInput(char *aName, AudioDataListener *aListener) override;
|
||||
void OpenAudioInputImpl(CubebUtils::AudioDeviceID aID,
|
||||
AudioDataListener *aListener);
|
||||
virtual nsresult OpenAudioInput(CubebUtils::AudioDeviceID aID,
|
||||
AudioDataListener *aListener) override;
|
||||
void CloseAudioInputImpl(AudioDataListener *aListener);
|
||||
virtual void CloseAudioInput(AudioDataListener *aListener) override;
|
||||
|
||||
|
@ -582,6 +584,15 @@ public:
|
|||
*/
|
||||
int32_t mPortCount;
|
||||
|
||||
/**
|
||||
* Devices to use for cubeb input & output, or NULL for no input (void*),
|
||||
* and boolean to control if we want input/output
|
||||
*/
|
||||
bool mInputWanted;
|
||||
CubebUtils::AudioDeviceID mInputDeviceID;
|
||||
bool mOutputWanted;
|
||||
CubebUtils::AudioDeviceID mOutputDeviceID;
|
||||
|
||||
// True if the graph needs another iteration after the current iteration.
|
||||
Atomic<bool> mNeedAnotherIteration;
|
||||
// GraphDriver may need a WakeUp() if something changes
|
||||
|
|
|
@ -44,6 +44,8 @@ GetUserMediaLog()
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
cubeb_device_collection* AudioInputCubeb::mDevices = nullptr;
|
||||
|
||||
MediaEngineWebRTC::MediaEngineWebRTC(MediaEnginePrefs &aPrefs)
|
||||
: mMutex("mozilla::MediaEngineWebRTC"),
|
||||
mVoiceEngine(nullptr),
|
||||
|
@ -326,7 +328,14 @@ MediaEngineWebRTC::EnumerateAudioDevices(dom::MediaSourceEnum aMediaSource,
|
|||
// We've already seen this device, just append.
|
||||
aASources->AppendElement(aSource.get());
|
||||
} else {
|
||||
aSource = new MediaEngineWebRTCMicrophoneSource(mThread, mVoiceEngine, mAudioInput,
|
||||
AudioInput* audioinput = mAudioInput;
|
||||
if (true /*platform_supports_full_duplex*/) {
|
||||
// For cubeb, it has state (the selected ID
|
||||
// XXX just use the uniqueID for cubeb and support it everywhere, and get rid of this
|
||||
// XXX Small window where the device list/index could change!
|
||||
audioinput = new mozilla::AudioInputCubeb(mVoiceEngine);
|
||||
}
|
||||
aSource = new MediaEngineWebRTCMicrophoneSource(mThread, mVoiceEngine, audioinput,
|
||||
i, deviceName, uniqueId);
|
||||
mAudioSources.Put(uuid, aSource); // Hashtable takes ownership.
|
||||
aASources->AppendElement(aSource);
|
||||
|
@ -366,6 +375,7 @@ MediaEngineWebRTC::Shutdown()
|
|||
mVoiceEngine = nullptr;
|
||||
|
||||
mozilla::camera::Shutdown();
|
||||
AudioInputCubeb::CleanupGlobalData();
|
||||
|
||||
if (mThread) {
|
||||
mThread->Shutdown();
|
||||
|
|
|
@ -159,35 +159,66 @@ class AudioInputCubeb final : public AudioInput
|
|||
{
|
||||
public:
|
||||
explicit AudioInputCubeb(webrtc::VoiceEngine* aVoiceEngine) :
|
||||
AudioInput(aVoiceEngine), mDevices(nullptr) {}
|
||||
AudioInput(aVoiceEngine), mSelectedDevice(0)
|
||||
{
|
||||
// Force calculation of the indexes. We could keep them global
|
||||
// too... cleanup would be annoying
|
||||
int devices;
|
||||
GetNumOfRecordingDevices(devices);
|
||||
}
|
||||
|
||||
static void CleanupGlobalData()
|
||||
{
|
||||
if (mDevices) {
|
||||
// This doesn't require anything more than support for free()
|
||||
cubeb_device_collection_destroy(mDevices);
|
||||
mDevices = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int GetNumOfRecordingDevices(int& aDevices)
|
||||
{
|
||||
// devices = cubeb_get_num_devices(...)
|
||||
if (!mDevices) {
|
||||
if (CUBEB_OK != cubeb_enumerate_devices(CubebUtils::GetCubebContext(),
|
||||
CUBEB_DEVICE_TYPE_INPUT,
|
||||
&mDevices)) {
|
||||
return 0;
|
||||
}
|
||||
aDevices = 0;
|
||||
}
|
||||
// Calculate translation once (per AudioInput)
|
||||
if (mDeviceIndexes.Length() == 0) {
|
||||
for (uint32_t i = 0; i < mDevices->count; i++) {
|
||||
if (mDevices->device[i]->type == CUBEB_DEVICE_TYPE_INPUT && // paranoia
|
||||
mDevices->device[i]->state == CUBEB_DEVICE_STATE_ENABLED)
|
||||
(mDevices->device[i]->state == CUBEB_DEVICE_STATE_ENABLED ||
|
||||
mDevices->device[i]->state == CUBEB_DEVICE_STATE_UNPLUGGED))
|
||||
{
|
||||
aDevices++;
|
||||
// XXX to support device changes, we need to identify by name/UUID not index
|
||||
mDeviceIndexes.AppendElement(i);
|
||||
// XXX to support device changes, we need to identify by name/devid not index
|
||||
}
|
||||
}
|
||||
}
|
||||
aDevices = mDeviceIndexes.Length();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t DeviceIndex(int aIndex)
|
||||
{
|
||||
if (aIndex == -1) {
|
||||
aIndex = 0; // -1 = system default
|
||||
}
|
||||
if (aIndex >= (int) mDeviceIndexes.Length()) {
|
||||
return -1;
|
||||
}
|
||||
return mDeviceIndexes[aIndex]; // translate to mDevices index
|
||||
}
|
||||
|
||||
int GetRecordingDeviceName(int aIndex, char aStrNameUTF8[128],
|
||||
char aStrGuidUTF8[128])
|
||||
{
|
||||
if (!mDevices) {
|
||||
int32_t devindex = DeviceIndex(aIndex);
|
||||
if (!mDevices || devindex < 0) {
|
||||
return 1;
|
||||
}
|
||||
int devindex = aIndex == -1 ? 0 : aIndex;
|
||||
PR_snprintf(aStrNameUTF8, 128, "%s%s", aIndex == -1 ? "default: " : "",
|
||||
mDevices->device[devindex]->friendly_name);
|
||||
aStrGuidUTF8[0] = '\0';
|
||||
|
@ -203,12 +234,14 @@ public:
|
|||
|
||||
void StartRecording(MediaStreamGraph *aGraph, AudioDataListener *aListener)
|
||||
{
|
||||
MOZ_ASSERT(mDevices);
|
||||
|
||||
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> ptrVoERender;
|
||||
ptrVoERender = webrtc::VoEExternalMedia::GetInterface(mVoiceEngine);
|
||||
if (ptrVoERender) {
|
||||
ptrVoERender->SetExternalRecordingStatus(true);
|
||||
}
|
||||
aGraph->OpenAudioInput(nullptr, aListener);
|
||||
aGraph->OpenAudioInput(mDevices->device[mSelectedDevice]->devid, aListener);
|
||||
}
|
||||
|
||||
void StopRecording(MediaStreamGraph *aGraph, AudioDataListener *aListener)
|
||||
|
@ -218,21 +251,21 @@ public:
|
|||
|
||||
int SetRecordingDevice(int aIndex)
|
||||
{
|
||||
// Relevant with devid support
|
||||
int32_t devindex = DeviceIndex(aIndex);
|
||||
if (!mDevices || devindex < 0) {
|
||||
return 1;
|
||||
}
|
||||
mSelectedDevice = devindex;
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
~AudioInputCubeb() {
|
||||
{
|
||||
if (mDevices) {
|
||||
cubeb_device_collection_destroy(mDevices);
|
||||
mDevices = nullptr;
|
||||
}
|
||||
}
|
||||
~AudioInputCubeb() {}
|
||||
|
||||
private:
|
||||
cubeb_device_collection* mDevices;
|
||||
nsTArray<int> mDeviceIndexes;
|
||||
int mSelectedDevice;
|
||||
static cubeb_device_collection *mDevices;
|
||||
};
|
||||
|
||||
class AudioInputWebRTC final : public AudioInput
|
||||
|
|
Загрузка…
Ссылка в новой задаче