Skip to content

Commit

Permalink
This is the preliminary introduction for the code for the chrome.copr…
Browse files Browse the repository at this point in the history
…esence

API which enables the exchange short messages with nearby devices.

This is the audio handling code of the copresence core component. We'll be
open sourcing this code in phases, this is the first part. This CL includes
the code for the directive handler for copresence, and all related classes.
Including blundell@ for the OWNERs review to add this component.

R=dalecurtis@chromium.org, derat@chromium.org, jochen@chromium.org, xiyuan@chromium.org, blundell@chromium.org
BUG=365493

Review URL: https://codereview.chromium.org/419073002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@287900 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
rkc@chromium.org committed Aug 6, 2014
1 parent 83b651b commit ff0ed12
Show file tree
Hide file tree
Showing 24 changed files with 2,210 additions and 2 deletions.
14 changes: 14 additions & 0 deletions components/components_tests.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,20 @@
'invalidation/unacked_invalidation_set_unittest.cc',
],
}],
['OS != "ios" and OS != "android"', {
'sources': [
'copresence/handlers/audio/audio_directive_handler_unittest.cc',
'copresence/handlers/audio/audio_directive_list_unittest.cc',
'copresence/mediums/audio/audio_player_unittest.cc',
'copresence/mediums/audio/audio_recorder_unittest.cc',
'copresence/timed_map_unittest.cc',
],
'dependencies': [
# Dependencies for copresence.
'components.gyp:copresence',
'components.gyp:copresence_test_support',
],
}],
['chromeos==1', {
'sources!': [
'storage_monitor/storage_monitor_linux_unittest.cc',
Expand Down
31 changes: 29 additions & 2 deletions components/copresence.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
'type': 'static_library',
'dependencies': [
'../base/base.gyp:base',
'../content/content.gyp:content_common',
'../media/media.gyp:media',
'../media/media.gyp:shared_memory_support',
'../net/net.gyp:net',
'copresence_proto',
],
Expand All @@ -17,16 +20,40 @@
],
'sources': [
'copresence/copresence_client.cc',
'copresence/copresence_constants.cc',
'copresence/handlers/audio/audio_directive_handler.cc',
'copresence/handlers/audio/audio_directive_handler.h',
'copresence/handlers/audio/audio_directive_list.cc',
'copresence/handlers/audio/audio_directive_list.h',
'copresence/handlers/directive_handler.cc',
'copresence/handlers/directive_handler.h',
'copresence/mediums/audio/audio_player.cc',
'copresence/mediums/audio/audio_player.h',
'copresence/mediums/audio/audio_recorder.cc',
'copresence/mediums/audio/audio_recorder.h',
'copresence/public/copresence_client_delegate.h',
'copresence/public/copresence_client.h',
'copresence/public/copresence_constants.h',
'copresence/public/whispernet_client.h',
'copresence/rpc/rpc_handler.cc',
'copresence/rpc/rpc_handler.h',
'copresence/rpc/rpc_handler.cc'
'copresence/rpc/rpc_handler.h'
'copresence/timed_map.h',
],
'export_dependent_settings': [
'copresence_proto',
],
},
{
'target_name': 'copresence_test_support',
'type': 'static_library',
'include_dirs': [
'..',
],
'sources': [
'copresence/test/audio_test_support.cc',
'copresence/test/audio_test_support.h',
],
},
{
# Protobuf compiler / generate rule for copresence.
# GN version: //components/copresence/proto
Expand Down
15 changes: 15 additions & 0 deletions components/copresence/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,31 @@
static_library("copresence") {
sources = [
"copresence_client.cc",
"copresence_constants.cc",
"handlers/audio/audio_directive_handler.cc",
"handlers/audio/audio_directive_handler.h",
"handlers/audio/audio_directive_list.cc",
"handlers/audio/audio_directive_list.h",
"handlers/directive_handler.cc",
"handlers/directive_handler.h",
"mediums/audio/audio_player.cc",
"mediums/audio/audio_player.h",
"mediums/audio/audio_recorder.cc",
"mediums/audio/audio_recorder.h",
"public/copresence_client_delegate.h",
"public/copresence_client.h",
"public/copresence_constants.h",
"public/whispernet_client.h",
"rpc/rpc_handler.cc",
"rpc/rpc_handler.h",
"timed_map.h",
]

deps = [
"//base",
"//components/copresence/proto",
"//content",
"//media",
"//net",
]
}
3 changes: 3 additions & 0 deletions components/copresence/DEPS
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
include_rules = [
"+base",
"+content/public/browser",
"+content/public/test",
"+media",
]
16 changes: 16 additions & 0 deletions components/copresence/copresence_constants.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/copresence/public/copresence_constants.h"

namespace copresence {

const int kDefaultRepetitions = 5;
const float kDefaultSampleRate = 48000.0f;
const int kDefaultBitsPerSample = 16;
const float kDefaultCarrierFrequency = 18500.0f;
const int kDefaultChannels = 2;
const media::ChannelLayout kDefaultChannelLayout = media::CHANNEL_LAYOUT_STEREO;

} // namespace copresence
113 changes: 113 additions & 0 deletions components/copresence/handlers/audio/audio_directive_handler.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/copresence/handlers/audio/audio_directive_handler.h"

#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "components/copresence/mediums/audio/audio_player.h"
#include "components/copresence/mediums/audio/audio_recorder.h"
#include "components/copresence/proto/data.pb.h"
#include "media/base/audio_bus.h"

namespace copresence {

// Public methods.

AudioDirectiveHandler::AudioDirectiveHandler(
const AudioRecorder::DecodeSamplesCallback& decode_cb,
const AudioDirectiveList::EncodeTokenCallback& encode_cb)
: directive_list_(encode_cb,
base::Bind(&AudioDirectiveHandler::ExecuteNextTransmit,
base::Unretained(this))),
player_(NULL),
recorder_(NULL),
decode_cb_(decode_cb) {
}

AudioDirectiveHandler::~AudioDirectiveHandler() {
if (player_)
player_->Finalize();
if (recorder_)
recorder_->Finalize();
}

void AudioDirectiveHandler::Initialize() {
player_ = new AudioPlayer();
player_->Initialize();

recorder_ = new AudioRecorder(decode_cb_);
recorder_->Initialize();
}

void AudioDirectiveHandler::AddInstruction(const TokenInstruction& instruction,
base::TimeDelta ttl) {
switch (instruction.token_instruction_type()) {
case TRANSMIT:
DVLOG(2) << "Audio Transmit Directive received. Token: "
<< instruction.token_id()
<< " with TTL=" << ttl.InMilliseconds();
// TODO(rkc): Fill in the op_id once we get it from the directive.
directive_list_.AddTransmitDirective(
instruction.token_id(), std::string(), ttl);
break;
case RECEIVE:
DVLOG(2) << "Audio Receive Directive received. TTL="
<< ttl.InMilliseconds();
// TODO(rkc): Fill in the op_id once we get it from the directive.
directive_list_.AddReceiveDirective(std::string(), ttl);
break;
case UNKNOWN_TOKEN_INSTRUCTION_TYPE:
default:
LOG(WARNING) << "Unknown Audio Transmit Directive received.";
}
// ExecuteNextTransmit will be called by directive_list_ when Add is done.
ExecuteNextReceive();
}

// Protected methods.

void AudioDirectiveHandler::PlayAudio(
const scoped_refptr<media::AudioBusRefCounted>& samples,
base::TimeDelta duration) {
player_->Play(samples);
stop_playback_timer_.Start(
FROM_HERE, duration, this, &AudioDirectiveHandler::StopPlayback);
}

void AudioDirectiveHandler::RecordAudio(base::TimeDelta duration) {
recorder_->Record();
stop_recording_timer_.Start(
FROM_HERE, duration, this, &AudioDirectiveHandler::StopRecording);
}

// Private methods.

void AudioDirectiveHandler::StopPlayback() {
player_->Stop();
DVLOG(2) << "Done playing audio.";
ExecuteNextTransmit();
}

void AudioDirectiveHandler::StopRecording() {
recorder_->Stop();
DVLOG(2) << "Done recording audio.";
ExecuteNextReceive();
}

void AudioDirectiveHandler::ExecuteNextTransmit() {
scoped_ptr<AudioDirective> transmit(directive_list_.GetNextTransmit());
if (transmit)
PlayAudio(transmit->samples, transmit->end_time - base::Time::Now());
}

void AudioDirectiveHandler::ExecuteNextReceive() {
scoped_ptr<AudioDirective> receive(directive_list_.GetNextReceive());
if (receive)
RecordAudio(receive->end_time - base::Time::Now());
}

} // namespace copresence
76 changes: 76 additions & 0 deletions components/copresence/handlers/audio/audio_directive_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_HANDLER_
#define COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_HANDLER_

#include <vector>

#include "base/basictypes.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/copresence/handlers/audio/audio_directive_list.h"
#include "components/copresence/mediums/audio/audio_recorder.h"
#include "components/copresence/proto/data.pb.h"

namespace media {
class AudioBusRefCounted;
}

namespace copresence {

class AudioPlayer;

// The AudioDirectiveHandler handles audio transmit and receive instructions.
class AudioDirectiveHandler {
public:
AudioDirectiveHandler(
const AudioRecorder::DecodeSamplesCallback& decode_cb,
const AudioDirectiveList::EncodeTokenCallback& encode_cb);
virtual ~AudioDirectiveHandler();

// Do not use this class before calling this.
void Initialize();

// Adds an instruction to our handler. The instruction will execute and be
// removed after the ttl expires.
void AddInstruction(const copresence::TokenInstruction& instruction,
base::TimeDelta ttl_ms);

protected:
// Protected and virtual since we want to be able to mock these out.
virtual void PlayAudio(
const scoped_refptr<media::AudioBusRefCounted>& samples,
base::TimeDelta duration);
virtual void RecordAudio(base::TimeDelta duration);

private:
void StopPlayback();
void StopRecording();

// Execute the next active transmit instruction.
void ExecuteNextTransmit();
// Execute the next active receive instruction.
void ExecuteNextReceive();

AudioDirectiveList directive_list_;

// The next two pointers are self-deleting. When we call Finalize on them,
// they clean themselves up on the Audio thread.
AudioPlayer* player_;
AudioRecorder* recorder_;

AudioRecorder::DecodeSamplesCallback decode_cb_;

base::OneShotTimer<AudioDirectiveHandler> stop_playback_timer_;
base::OneShotTimer<AudioDirectiveHandler> stop_recording_timer_;

DISALLOW_COPY_AND_ASSIGN(AudioDirectiveHandler);
};

} // namespace copresence

#endif // COMPONENTS_COPRESENCE_HANDLERS_AUDIO_AUDIO_DIRECTIVE_HANDLER_
Loading

0 comments on commit ff0ed12

Please sign in to comment.