summaryrefslogtreecommitdiffstats
path: root/variablespeed/jni
diff options
context:
space:
mode:
Diffstat (limited to 'variablespeed/jni')
-rw-r--r--variablespeed/jni/Android.mk44
-rw-r--r--variablespeed/jni/decode_buffer.cc86
-rw-r--r--variablespeed/jni/decode_buffer.h59
-rw-r--r--variablespeed/jni/hlogging.h32
-rw-r--r--variablespeed/jni/integral_types.h33
-rw-r--r--variablespeed/jni/jni_entry.cc96
-rw-r--r--variablespeed/jni/macros.h66
-rw-r--r--variablespeed/jni/no_synchronization.h50
-rw-r--r--variablespeed/jni/profile_timer.h52
-rw-r--r--variablespeed/jni/ring_buffer.cc154
-rw-r--r--variablespeed/jni/ring_buffer.h117
-rw-r--r--variablespeed/jni/sola_time_scaler.cc366
-rw-r--r--variablespeed/jni/sola_time_scaler.h165
-rw-r--r--variablespeed/jni/variablespeed.cc864
-rw-r--r--variablespeed/jni/variablespeed.h167
15 files changed, 0 insertions, 2351 deletions
diff --git a/variablespeed/jni/Android.mk b/variablespeed/jni/Android.mk
deleted file mode 100644
index 98b9325..0000000
--- a/variablespeed/jni/Android.mk
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# 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.
-#
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-# TODO: Remove the .cc extension, just .cpp.
-
-# Add in extra warnings.
-LOCAL_CFLAGS += -Wall
-LOCAL_CPPFLAGS += -Wall
-
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_MODULE := libvariablespeed
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
- variablespeed.cc \
- ring_buffer.cc \
- sola_time_scaler.cc \
- jni_entry.cc \
- decode_buffer.cc \
-
-LOCAL_C_INCLUDES := \
- $(call include-path-for, wilhelm) \
-
-LOCAL_SHARED_LIBRARIES := \
- libOpenSLES \
- liblog \
-
-LOCAL_CLANG := true
-include $(BUILD_SHARED_LIBRARY)
diff --git a/variablespeed/jni/decode_buffer.cc b/variablespeed/jni/decode_buffer.cc
deleted file mode 100644
index a08cfd6..0000000
--- a/variablespeed/jni/decode_buffer.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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 <decode_buffer.h>
-
-namespace {
-
-static const size_t kNumberOfBytesPerSample = 2;
-
-} // namespace
-
-DecodeBuffer::DecodeBuffer(size_t sizeOfOneBuffer, size_t maxSize)
- : sizeOfOneBuffer_(sizeOfOneBuffer), maxSize_(maxSize),
- start_(0), end_(0), advancedCount_(0), data_() {
- Clear();
-}
-
-DecodeBuffer::~DecodeBuffer() {
- Clear();
-}
-
-size_t DecodeBuffer::GetSizeInBytes() const {
- return kNumberOfBytesPerSample * (end_ - start_);
-}
-
-bool DecodeBuffer::IsTooLarge() const {
- return GetSizeInBytes() > maxSize_;
-}
-
-void DecodeBuffer::AddData(int8_t* pointer, size_t lengthInBytes) {
- for (size_t i = 0; i < lengthInBytes / kNumberOfBytesPerSample; ++i) {
- PushValue(reinterpret_cast<int16*>(pointer)[i]);
- }
-}
-
-void DecodeBuffer::Clear() {
- while (data_.size() > 0) {
- delete[] data_.front();
- data_.erase(data_.begin());
- }
- start_ = 0;
- end_ = 0;
- advancedCount_ = 0;
-}
-
-size_t DecodeBuffer::GetTotalAdvancedCount() const {
- return advancedCount_;
-}
-
-void DecodeBuffer::AdvanceHeadPointerShorts(size_t numberOfShorts) {
- start_ += numberOfShorts;
- while (start_ > sizeOfOneBuffer_) {
- data_.push_back(data_.front());
- data_.erase(data_.begin());
- start_ -= sizeOfOneBuffer_;
- end_ -= sizeOfOneBuffer_;
- }
- advancedCount_ += numberOfShorts;
-}
-
-void DecodeBuffer::PushValue(int16 value) {
- size_t bufferIndex = end_ / sizeOfOneBuffer_;
- if (bufferIndex >= data_.size()) {
- data_.push_back(new int16[sizeOfOneBuffer_]);
- }
- data_.at(bufferIndex)[end_ % sizeOfOneBuffer_] = value;
- ++end_;
-}
-
-int16 DecodeBuffer::GetAtIndex(size_t index) {
- return data_.at((start_ + index) / sizeOfOneBuffer_)
- [(start_ + index) % sizeOfOneBuffer_];
-}
diff --git a/variablespeed/jni/decode_buffer.h b/variablespeed/jni/decode_buffer.h
deleted file mode 100644
index 2f1aa71..0000000
--- a/variablespeed/jni/decode_buffer.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef FRAMEWORKS_EX_VARIABLESPEED_JNI_DECODE_BUFFER_H_
-#define FRAMEWORKS_EX_VARIABLESPEED_JNI_DECODE_BUFFER_H_
-
-#include <integral_types.h>
-#include <macros.h>
-#include <stdlib.h>
-#include <vector>
-
-// DecodeBuffer is used to store arrays of int16 values for audio.
-//
-// This class is not thread-safe. You should provide your own
-// synchronization if you wish to use it from multiple threads.
-class DecodeBuffer {
- public:
- DecodeBuffer(size_t sizeOfOneBuffer, size_t maxSize);
- virtual ~DecodeBuffer();
- size_t GetSizeInBytes() const;
- void AddData(int8_t* pointer, size_t lengthInBytes);
- void Clear();
- void AdvanceHeadPointerShorts(size_t numberOfShorts);
- int16 GetAtIndex(size_t index);
- bool IsTooLarge() const;
- size_t GetTotalAdvancedCount() const;
-
- private:
- void PushValue(int16 value);
-
- size_t sizeOfOneBuffer_;
- size_t maxSize_;
- size_t start_;
- size_t end_;
- size_t advancedCount_;
- // This vector isn't ideal because we perform a number of queue-like
- // operations: namely removing from the front and appending at the back.
- // However we also need constant-time access to the elements of this
- // vector, and therefore it's not good enough to use a std::queue.
- // In practice this data structure choice doesn't seem to be a bottleneck.
- std::vector<int16*> data_;
-
- DISALLOW_COPY_AND_ASSIGN(DecodeBuffer);
-};
-
-#endif // FRAMEWORKS_EX_VARIABLESPEED_JNI_DECODE_BUFFER_H_
diff --git a/variablespeed/jni/hlogging.h b/variablespeed/jni/hlogging.h
deleted file mode 100644
index 056f5a3..0000000
--- a/variablespeed/jni/hlogging.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef FRAMEWORKS_EX_VARIABLESPEED_JNI_HLOGGING_H_
-#define FRAMEWORKS_EX_VARIABLESPEED_JNI_HLOGGING_H_
-
-#include <integral_types.h>
-#include <macros.h>
-#include <android/log.h>
-
-// Simple logging macros.
-#define LOG_TAG "VariableSpeed"
-#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
-#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
-#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
-#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
-#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
-
-#endif // FRAMEWORKS_EX_VARIABLESPEED_JNI_HLOGGING_H_
diff --git a/variablespeed/jni/integral_types.h b/variablespeed/jni/integral_types.h
deleted file mode 100644
index 8927d7c..0000000
--- a/variablespeed/jni/integral_types.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef FRAMEWORKS_EX_VARIABLESPEED_JNI_INTEGRAL_TYPES_H_
-#define FRAMEWORKS_EX_VARIABLESPEED_JNI_INTEGRAL_TYPES_H_
-
-#include <cstring> // for size_t
-
-// Standard typedefs
-typedef signed char schar;
-typedef signed char int8;
-typedef short int16; // NOLINT
-typedef int int32;
-typedef long long int64; // NOLINT
-typedef unsigned char uint8;
-typedef unsigned short uint16; // NOLINT
-typedef unsigned int uint32;
-typedef unsigned long long uint64; // NOLINT
-
-#endif // FRAMEWORKS_EX_VARIABLESPEED_JNI_INTEGRAL_TYPES_H_
diff --git a/variablespeed/jni/jni_entry.cc b/variablespeed/jni/jni_entry.cc
deleted file mode 100644
index 20bcf3c..0000000
--- a/variablespeed/jni/jni_entry.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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 <stdlib.h>
-#include <assert.h>
-
-#include <jni.h>
-#include <variablespeed.h>
-
-// Quick #define to make sure I get all the JNI method calls right.
-#define JNI_METHOD(x, y) \
-JNIEXPORT y JNICALL \
-Java_com_android_ex_variablespeed_VariableSpeedNative_##x
-
-class MethodLog {
- public:
- explicit MethodLog(const char* name) : name_(name) {
- LOGV("+ %s", name);
- }
- virtual ~MethodLog() {
- LOGV("- %s", name_);
- }
-
- private:
- const char* name_;
-};
-
-extern "C" {
-JNI_METHOD(playFileDescriptor, void) (JNIEnv*, jclass, jint fd, jlong offset,
- jlong length) {
- MethodLog _("playFileDescriptor");
- AudioEngine::GetEngine()->PlayFileDescriptor(fd, offset, length);
-}
-
-JNI_METHOD(playUri, void) (JNIEnv* env, jclass, jstring uri) {
- MethodLog _("playUri");
- const char* utf8 = env->GetStringUTFChars(uri, NULL);
- CHECK(NULL != utf8);
- AudioEngine::GetEngine()->PlayUri(utf8);
-}
-
-JNI_METHOD(setVariableSpeed, void) (JNIEnv*, jclass, jfloat speed) {
- MethodLog _("setVariableSpeed");
- AudioEngine::GetEngine()->SetVariableSpeed(speed);
-}
-
-JNI_METHOD(startPlayback, void) (JNIEnv*, jclass) {
- MethodLog _("startPlayback");
- AudioEngine::GetEngine()->RequestStart();
-}
-
-JNI_METHOD(stopPlayback, void) (JNIEnv*, jclass) {
- MethodLog _("stopPlayback");
- AudioEngine::GetEngine()->RequestStop();
-}
-
-JNI_METHOD(getCurrentPosition, jint) (JNIEnv*, jclass) {
- return AudioEngine::GetEngine()->GetCurrentPosition();
-}
-
-JNI_METHOD(getTotalDuration, jint) (JNIEnv*, jclass) {
- return AudioEngine::GetEngine()->GetTotalDuration();
-}
-
-JNI_METHOD(initializeEngine, void) (JNIEnv*, jclass,
- jint targetFrames, jfloat windowDuration,
- jfloat windowOverlapDuration, jint maxPlayBufferCount,
- jfloat initialRate, jint decodeInitialSize, jint decodeMaxSize,
- jint startPositionMillis, jint audioStreamType) {
- MethodLog _("initializeEngine");
- AudioEngine *engine = new AudioEngine(targetFrames,
- windowDuration, windowOverlapDuration, maxPlayBufferCount, initialRate,
- decodeInitialSize, decodeMaxSize, startPositionMillis, audioStreamType);
- if (!AudioEngine::CompareAndSetEngine(NULL, engine)) {
- delete engine;
- }
-}
-
-JNI_METHOD(shutdownEngine, void) (JNIEnv*, jclass) {
- MethodLog _("shutdownEngine");
- AudioEngine::DeleteEngine();
-}
-} // extern "C"
diff --git a/variablespeed/jni/macros.h b/variablespeed/jni/macros.h
deleted file mode 100644
index c08d44b..0000000
--- a/variablespeed/jni/macros.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef FRAMEWORKS_EX_VARIABLESPEED_JNI_MACROS_H_
-#define FRAMEWORKS_EX_VARIABLESPEED_JNI_MACROS_H_
-
-#include <hlogging.h>
-
-inline float min(float a, float b) {
- return (a < b) ? a : b;
-}
-
-inline float max(float a, float b) {
- return (a > b) ? a : b;
-}
-
-template <class ForwardIterator>
- ForwardIterator min_element(ForwardIterator first, ForwardIterator last) {
- ForwardIterator lowest = first;
- if (first == last) return last;
- while (++first != last)
- if (*first < *lowest)
- lowest = first;
- return lowest;
-}
-
-// A macro to disallow the copy constructor and operator= functions
-// This should be used in the private: declarations for a class
-#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
- TypeName(const TypeName&); \
- void operator=(const TypeName&)
-
-#define CHECK(x) { \
- if (!(x)) { \
- LOGE("assertion failed: " #x); \
- LOGE("file: %s line: %d", __FILE__, __LINE__); \
- int* frob = NULL; \
- *frob = 5; \
- } \
-}
-
-template <class Dest, class Source>
-inline Dest bit_cast(const Source& source) {
- // Compile time assertion: sizeof(Dest) == sizeof(Source)
- // A compile error here means your Dest and Source have different sizes.
- typedef char VerifySizesAreEqual [sizeof(Dest) == sizeof(Source) ? 1 : -1]; // NOLINT
-
- Dest dest;
- memcpy(&dest, &source, sizeof(dest));
- return dest;
-}
-
-#endif // FRAMEWORKS_EX_VARIABLESPEED_JNI_MACROS_H_
diff --git a/variablespeed/jni/no_synchronization.h b/variablespeed/jni/no_synchronization.h
deleted file mode 100644
index 751ebd9..0000000
--- a/variablespeed/jni/no_synchronization.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef FRAMEWORKS_EX_VARIABLESPEED_JNI_NO_SYNCHRONIZATION_H_
-#define FRAMEWORKS_EX_VARIABLESPEED_JNI_NO_SYNCHRONIZATION_H_
-
-#include <macros.h>
-
-// We don't need any synchronization at the moment.
-// The sola_time_scaler (which is the code that uses this mutex class) is
-// currently being used in a single-threaded manner, driven from the main
-// PlayFromThisSource method in variablespeed.
-// As such no locking is actually required, and so this class contains a
-// fake mutex that does nothing.
-
-class Mutex {
- public:
- Mutex() {}
- virtual ~Mutex() {}
- void Lock() {}
- void Unlock() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Mutex);
-};
-
-class MutexLock {
- public:
- explicit MutexLock(Mutex* mu) : mu_(mu) {}
- virtual ~MutexLock() {}
-
- private:
- Mutex* const mu_;
- DISALLOW_COPY_AND_ASSIGN(MutexLock);
-};
-
-#endif // FRAMEWORKS_EX_VARIABLESPEED_JNI_NO_SYNCHRONIZATION_H_
diff --git a/variablespeed/jni/profile_timer.h b/variablespeed/jni/profile_timer.h
deleted file mode 100644
index 6844cb2..0000000
--- a/variablespeed/jni/profile_timer.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef FRAMEWORKS_EX_VARIABLESPEED_JNI_PROFILE_TIMER_H_
-#define FRAMEWORKS_EX_VARIABLESPEED_JNI_PROFILE_TIMER_H_
-
-#include <hlogging.h>
-#include <time.h>
-
-#include <string>
-
-// Simple profiler for debugging method call duration.
-class Timer {
- public:
- Timer() : startTime_(clock()) {
- }
-
- virtual ~Timer() {
- PrintElapsed("destructor");
- }
-
- void PrintElapsed(const char* message) {
- clock_t endTime(clock());
- LOGD("Timer(%s): %d ms", message,
- static_cast<int>((endTime - startTime_) * 1000 / CLOCKS_PER_SEC));
- }
-
- size_t GetElapsed() {
- clock_t endTime(clock());
- return (endTime - startTime_) * 1000 / CLOCKS_PER_SEC;
- }
-
- private:
- clock_t startTime_;
-
- DISALLOW_COPY_AND_ASSIGN(Timer);
-};
-
-#endif // FRAMEWORKS_EX_VARIABLESPEED_JNI_PROFILE_TIMER_H_
diff --git a/variablespeed/jni/ring_buffer.cc b/variablespeed/jni/ring_buffer.cc
deleted file mode 100644
index 61c1490..0000000
--- a/variablespeed/jni/ring_buffer.cc
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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 "ring_buffer.h"
-
-#include <algorithm>
-
-#include "integral_types.h"
-
-namespace video_editing {
-
-void RingBuffer::Init(int size, int num_channels, int num_readers) {
- size_ = size;
- num_channels_ = num_channels;
- num_readers_ = num_readers;
- temp_read_buffer_size_ = 1024;
- initialized_ = true;
- Reset();
-}
-
-RingBuffer::RingBuffer()
- : initialized_(false), samples_(NULL),
- num_readers_(0), temp_read_buffer_(NULL) {
-}
-
-RingBuffer::~RingBuffer() {
- delete[] samples_;
- delete[] temp_read_buffer_;
-}
-
-void RingBuffer::Reset() {
- delete[] samples_;
- samples_ = new float[size_ * num_channels_];
- memset(samples_, 0,
- size_ * num_channels_ * sizeof(samples_[0]));
-
- temp_read_buffer_size_ = 1024;
- delete[] temp_read_buffer_;
- temp_read_buffer_ = new float[temp_read_buffer_size_ * num_channels_];
- memset(temp_read_buffer_, 0,
- temp_read_buffer_size_ * num_channels_ * sizeof(samples_[0]));
- readers_.clear();
- for (int i = 0; i < num_readers_; ++i) {
- readers_.push_back(0LL);
- }
- head_logical_ = 0LL;
- head_ = 0;
-}
-
-int RingBuffer::available(int reader) const {
- return head_logical_ - readers_[reader];
-}
-
-int RingBuffer::overhead() const {
- int64 tail = GetTail();
- return tail + size_ - head_logical_;
-}
-
-int64 RingBuffer::GetTail() const {
- return *std::min_element(readers_.begin(), readers_.end());
-}
-
-int64 RingBuffer::Tell(int reader) const {
- return readers_[reader];
-}
-
-void RingBuffer::Seek(int reader, int64 position) {
- readers_[reader] = position;
-}
-
-void RingBuffer::Write(const float* samples, int num_frames) {
- if (!num_frames) {
- return;
- }
- if (head_ + num_frames <= size_) {
- memcpy(samples_ + head_ * num_channels_, samples,
- num_frames * num_channels_ * sizeof(samples[0]));
- head_ += num_frames;
- } else {
- int overhead = size_ - head_;
- memcpy(samples_ + head_ * num_channels_, samples,
- num_channels_ * overhead * sizeof(samples[0]));
- head_ = num_frames - overhead;
- memcpy(samples_, samples + overhead * num_channels_,
- num_channels_ * head_ * sizeof(samples[0]));
- }
- head_logical_ += num_frames;
-}
-
-void RingBuffer::Copy(int reader, float* destination, int num_frames) const {
- int pos = Tell(reader) % size_;
- if (pos + num_frames <= size_) {
- memcpy(destination, samples_ + pos * num_channels_,
- num_channels_ * num_frames * sizeof(destination[0]));
- } else {
- int wrapped = size_ - pos;
- memcpy(destination, samples_ + pos * num_channels_,
- num_channels_ * wrapped * sizeof(destination[0]));
- int remaining = num_frames - wrapped;
- memcpy(destination + wrapped * num_channels_, samples_,
- num_channels_ * remaining * sizeof(destination[0]));
- }
-}
-
-float* RingBuffer::GetPointer(int reader, int num_frames) {
- int pos = Tell(reader) % size_;
- if (pos + num_frames <= size_) {
- return samples_ + pos * num_channels_;
- } else {
- if (num_frames > temp_read_buffer_size_) {
- temp_read_buffer_size_ = num_frames;
- delete[] temp_read_buffer_;
- temp_read_buffer_ =
- new float[temp_read_buffer_size_ * num_channels_]; // NOLINT
- }
- Copy(reader, temp_read_buffer_, num_frames);
- return temp_read_buffer_;
- }
-}
-
-void RingBuffer::MergeBack(int reader, const float* source, int num_frames) {
- // If the source pointer is not the temporary buffer,
- // data updates were performed in place, so there is nothing to do.
- // Otherwise, copy samples from the temp buffer back to the ring buffer.
- if (source == temp_read_buffer_) {
- int pos = Tell(reader) % size_;
- if (pos + num_frames <= size_) {
- memcpy(samples_ + (pos * num_channels_), source,
- num_channels_ * num_frames * sizeof(source[0]));
- } else {
- int wrapped = size_ - pos;
- memcpy(samples_ + (pos * num_channels_), source,
- num_channels_ * wrapped * sizeof(source[0]));
- int remaining = num_frames - wrapped;
- memcpy(samples_, source + (wrapped * num_channels_),
- num_channels_ * remaining * sizeof(source[0]));
- }
- }
-}
-
-} // namespace video_editing
diff --git a/variablespeed/jni/ring_buffer.h b/variablespeed/jni/ring_buffer.h
deleted file mode 100644
index 8afe436..0000000
--- a/variablespeed/jni/ring_buffer.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef FRAMEWORKS_EX_VARIABLESPEED_JNI_RING_BUFFER_H_
-#define FRAMEWORKS_EX_VARIABLESPEED_JNI_RING_BUFFER_H_
-
-#include <vector>
-
-#include "integral_types.h"
-#include "macros.h"
-
-// Circular buffer of multichannel audio, maintaining the position of the
-// writing head and several reading head, and providing a method for
-// accessing a contiguous block (through direct reference or the copy in a
-// temporary read buffer in case the requested block crosses the buffer
-// boundaries).
-//
-// This code is not thread-safe.
-
-namespace video_editing {
-
-class RingBuffer {
- public:
- RingBuffer();
- virtual ~RingBuffer();
-
- // Initializes a RingBuffer.
- // @param size: size of the buffer in frames.
- // @param num_channels: number of channels of the original audio.
- // @param num_readers: number of reading heads.
- void Init(int size, int num_channels, int num_readers);
-
- // Gets the position of a reading head.
- // @param reader reading head index.
- // @returns position pointed to by the #reader reading head.
- int64 Tell(int reader) const;
-
- // Moves a reading head.
- // @param reader reading head index.
- // @param position target position.
- void Seek(int reader, int64 position);
-
- // Reads samples for a reading head.
- // @param reader reading head index.
- // @param num_frames number of frames to read.
- // @param destination float buffer to which the samples will be written.
- void Copy(int reader, float* destination, int num_frames) const;
-
- // Writes samples.
- // @param samples float buffer containing the samples.
- // @param num_frames number of frames to write.
- void Write(const float* samples, int num_frames);
-
- // Flushes the content of the buffer and reset the position of the heads.
- void Reset();
-
- // Returns the number of frames we can still write.
- int overhead() const;
-
- // Returns the number of frames we can read for a given reader.
- // @param reader reading head index.
- int available(int reader) const;
-
- // Returns a pointer to num_frames x num_channels contiguous samples for
- // a given reader. In most cases this directly returns a pointer to the
- // data in the ring buffer. However, if the required block wraps around the
- // boundaries of the ring buffer, the data is copied to a temporary buffer
- // owned by the RingBuffer object.
- // @param reader reading head index.
- // @param num_frames number of frames to read.
- // @returns pointer to a continuous buffer containing num_frames.
- float* GetPointer(int reader, int num_frames);
-
- // Merges updated data back into the ring buffer, if it was updated in
- // the temporary buffer. This operation follows a GetPointer() that
- // was used to obtain data to rewrite. The buffer address supplied
- // here must match the one returned by GetPointer().
- // @param reader reading head index.
- // @param source pointer to a continuous buffer containing num_frames.
- // @param num_frames number of frames to copy back to the ring buffer.
- void MergeBack(int reader, const float* source, int num_frames);
-
- private:
- // Returns the position of the laziest reader.
- int64 GetTail() const;
-
- bool initialized_;
- float* samples_;
- std::vector<int64> readers_;
- int size_;
- int num_channels_;
- int num_readers_;
- int64 head_logical_;
- int head_;
-
- float* temp_read_buffer_;
- int temp_read_buffer_size_;
-
- DISALLOW_COPY_AND_ASSIGN(RingBuffer);
-};
-
-} // namespace video_editing
-
-#endif // FRAMEWORKS_EX_VARIABLESPEED_JNI_RING_BUFFER_H_
diff --git a/variablespeed/jni/sola_time_scaler.cc b/variablespeed/jni/sola_time_scaler.cc
deleted file mode 100644
index 1ff1236..0000000
--- a/variablespeed/jni/sola_time_scaler.cc
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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 "sola_time_scaler.h"
-
-#include <math.h>
-#include <hlogging.h>
-#include <algorithm>
-
-#include "ring_buffer.h"
-
-#define FLAGS_sola_ring_buffer 2.0
-#define FLAGS_sola_enable_correlation true
-
-
-namespace video_editing {
-
-// Returns a cross-correlation score for the specified buffers.
-int SolaAnalyzer::Correlate(const float* buffer1, const float* buffer2,
- int num_frames) {
- CHECK(initialized_);
-
- int score = 0;
- num_frames *= num_channels_;
- while (num_frames-- > 0) {
- // Increment the score if the sign bits match.
- score += ((bit_cast<int32>(*buffer1++) ^ bit_cast<int32>(*buffer2++)) >= 0)
- ? 1 : 0;
- }
- return score;
-}
-
-// Trivial SolaAnalyzer class to bypass correlation.
-class SolaBypassAnalyzer : public SolaAnalyzer {
- public:
- SolaBypassAnalyzer() { }
- virtual int Correlate(const float*, const float*, int num_frames) {
- return num_frames * num_channels_;
- }
-};
-
-
-// Default constructor.
-SolaTimeScaler::SolaTimeScaler()
- : input_buffer_(NULL), output_buffer_(NULL), analyzer_(NULL) {
- sample_rate_ = 0;
- num_channels_ = 0;
-
- draining_ = false;
- initialized_ = false;
-}
-
-SolaTimeScaler::~SolaTimeScaler() {
- delete input_buffer_;
- delete output_buffer_;
- delete analyzer_;
-}
-
-// Injects a SolaAnalyzer instance for analyzing signal frames.
-void SolaTimeScaler::set_analyzer(SolaAnalyzer* analyzer) {
- MutexLock lock(&mutex_); // lock out processing while updating
- delete analyzer_;
- analyzer_ = analyzer;
-}
-
-// Initializes a SOLA timescaler.
-void SolaTimeScaler::Init(double sample_rate,
- int num_channels,
- double initial_speed,
- double window_duration,
- double overlap_duration) {
- MutexLock lock(&mutex_); // lock out processing while updating
-
- sample_rate_ = sample_rate;
- num_channels_ = num_channels;
- speed_ = initial_speed;
- window_duration_ = window_duration;
- overlap_duration_ = overlap_duration;
-
- initialized_ = true;
- GenerateParameters();
- Reset();
-}
-
-// Adjusts the rate scaling factor.
-void SolaTimeScaler::set_speed(double speed) {
- MutexLock lock(&mutex_); // lock out processing while updating
-
- speed_ = speed;
- GenerateParameters();
-}
-
-// Generates processing parameters from the current settings.
-void SolaTimeScaler::GenerateParameters() {
- if (speed_ < 0.1) {
- LOGE("Requested speed %fx limited to 0.1x", speed_);
- speed_ = 0.1;
- } else if (speed_ > 8.0) {
- LOGE("Requested speed %fx limited to 8.0x", speed_);
- speed_ = 8.0;
- }
-
- ratio_ = 1.0 / speed_;
-
- num_window_frames_ = nearbyint(sample_rate_ * window_duration_);
-
- // Limit the overlap to half the window size, and round up to an odd number.
- // Half of overlap window (rounded down) is also a useful number.
- overlap_duration_ = min(overlap_duration_, window_duration_ / 2.0);
- num_overlap_frames_ = nearbyint(sample_rate_ * overlap_duration_);
- num_overlap_frames_ |= 1;
- half_overlap_frames_ = num_overlap_frames_ >> 1;
-
- if (speed_ >= 1.) {
- // For compression (speed up), adjacent input windows overlap in the output.
- input_window_offset_ = num_window_frames_;
- target_merge_offset_ = nearbyint(num_window_frames_ * ratio_);
- } else {
- // For expansion (slow down), each input window start point overlaps the
- // previous, and they are placed adjacently in the output
- // (+/- half the overlap size).
- input_window_offset_ = nearbyint(num_window_frames_ * speed_);
- target_merge_offset_ = num_window_frames_;
- }
-
- // Make sure we copy enough extra data to be able to perform a
- // frame correlation over the range of target merge point +/- half overlap,
- // even when the previous merge point was adjusted backwards a half overlap.
- max_frames_to_merge_ = max(num_window_frames_,
- target_merge_offset_ + (2 * num_overlap_frames_));
- min_output_to_hold_=
- max_frames_to_merge_ + num_overlap_frames_ - target_merge_offset_;
-}
-
-// The input buffer has one writer and reader.
-// The output buffer has one reader/updater, and one reader/consumer.
-static const int kInputReader = 0;
-static const int kOutputAnalysis = 0;
-static const int kOutputConsumer = 1;
-
-void SolaTimeScaler::Reset() {
- CHECK(initialized_);
- double duration = max(FLAGS_sola_ring_buffer, 20. * window_duration_);
- draining_ = false;
-
- delete input_buffer_;
- input_buffer_ = new RingBuffer();
- input_buffer_->Init(static_cast<int>
- (sample_rate_ * duration), num_channels_, 1);
-
- delete output_buffer_;
- output_buffer_ = new RingBuffer();
- output_buffer_->Init(static_cast<int>
- (sample_rate_ * ratio_ * duration), num_channels_, 2);
-
- if (analyzer_ == NULL) {
- if (FLAGS_sola_enable_correlation) {
- analyzer_ = new SolaAnalyzer();
- } else {
- analyzer_ = new SolaBypassAnalyzer();
- }
- }
- analyzer_->Init(sample_rate_, num_channels_);
-}
-
-// Returns the number of frames that the input buffer can accept.
-int SolaTimeScaler::input_limit() const {
- CHECK(initialized_);
- return input_buffer_->overhead();
-}
-
-// Returns the number of available output frames.
-int SolaTimeScaler::available() {
- CHECK(initialized_);
-
- int available = output_buffer_->available(kOutputConsumer);
- if (available > min_output_to_hold_) {
- available -= min_output_to_hold_;
- } else if (draining_) {
- Process();
- available = output_buffer_->available(kOutputConsumer);
- if (available > min_output_to_hold_) {
- available -= min_output_to_hold_;
- }
- } else {
- available = 0;
- }
- return available;
-}
-
-void SolaTimeScaler::Drain() {
- CHECK(initialized_);
-
- draining_ = true;
-}
-
-
-// Feeds audio to the timescaler, and processes as much data as possible.
-int SolaTimeScaler::InjectSamples(float* buffer, int num_frames) {
- CHECK(initialized_);
-
- // Do not write more frames than the buffer can accept.
- num_frames = min(input_limit(), num_frames);
- if (!num_frames) {
- return 0;
- }
-
- // Copy samples to the input buffer and then process whatever can be consumed.
- input_buffer_->Write(buffer, num_frames);
- Process();
- return num_frames;
-}
-
-// Retrieves audio data from the timescaler.
-int SolaTimeScaler::RetrieveSamples(float* buffer, int num_frames) {
- CHECK(initialized_);
-
- // Do not read more frames than available.
- num_frames = min(available(), num_frames);
- if (!num_frames) {
- return 0;
- }
-
- output_buffer_->Copy(kOutputConsumer, buffer, num_frames);
- output_buffer_->Seek(kOutputConsumer,
- output_buffer_->Tell(kOutputConsumer) + num_frames);
-
- return num_frames;
-}
-
-// Munges input samples to produce output.
-bool SolaTimeScaler::Process() {
- CHECK(initialized_);
- bool generated_data = false;
-
- // We can only process data if there is sufficient input available
- // (or we are draining the latency), and there is sufficient room
- // for output to be merged.
- while (((input_buffer_->available(kInputReader) > max_frames_to_merge_) ||
- draining_) && (output_buffer_->overhead() >= max_frames_to_merge_)) {
- MutexLock lock(&mutex_); // lock out updates while processing each window
-
- // Determine the number of samples to merge into the output.
- int input_count =
- min(input_buffer_->available(kInputReader), max_frames_to_merge_);
- if (input_count == 0) {
- break;
- }
- // The input reader always points to the next window to process.
- float* input_pointer = input_buffer_->GetPointer(kInputReader, input_count);
-
- // The analysis reader always points to the ideal target merge point,
- // minus half an overlap window (ie, the starting point for correlation).
- // That means the available data from that point equals the number
- // of samples that must be cross-faded.
- int output_merge_cnt = output_buffer_->available(kOutputAnalysis);
- float* output_pointer =
- output_buffer_->GetPointer(kOutputAnalysis, output_merge_cnt);
-
- // If there is not enough data to do a proper correlation,
- // just merge at the ideal target point. Otherwise,
- // find the best correlation score, working from the center out.
- int merge_offset = min(output_merge_cnt, half_overlap_frames_);
-
- if ((output_merge_cnt >= (2 * num_overlap_frames_)) &&
- (input_count >= num_overlap_frames_)) {
- int best_offset = merge_offset;
- int best_score = 0;
- int score;
- for (int i = 0; i <= half_overlap_frames_; ++i) {
- score = analyzer_->Correlate(input_pointer,
- output_pointer + ((merge_offset + i) * num_channels_),
- num_overlap_frames_);
- if (score > best_score) {
- best_score = score;
- best_offset = merge_offset + i;
- if (score == (num_overlap_frames_ * num_channels_)) {
- break; // It doesn't get better than perfect.
- }
- }
- if (i > 0) {
- score = analyzer_->Correlate(input_pointer,
- output_pointer + ((merge_offset - i) * num_channels_),
- num_overlap_frames_);
- if (score > best_score) {
- best_score = score;
- best_offset = merge_offset - i;
- if (score == (num_overlap_frames_ * num_channels_)) {
- break; // It doesn't get better than perfect.
- }
- }
- }
- }
- merge_offset = best_offset;
- } else if ((output_merge_cnt > 0) && !draining_) {
- LOGE("no correlation performed");
- }
-
- // Crossfade the overlap between input and output, and then
- // copy in the remaining input.
- int crossfade_count = max(0, (output_merge_cnt - merge_offset));
- crossfade_count = min(crossfade_count, input_count);
- int remaining_count = input_count - crossfade_count;
-
- float* merge_pointer = output_pointer + (merge_offset * num_channels_);
- float flt_count = static_cast<float>(crossfade_count);
- for (int i = 0; i < crossfade_count; ++i) {
- // Linear cross-fade, for now.
- float input_scale = static_cast<float>(i) / flt_count;
- float output_scale = 1. - input_scale;
- for (int j = 0; j < num_channels_; ++j) {
- *merge_pointer = (*merge_pointer * output_scale) +
- (*input_pointer++ * input_scale);
- ++merge_pointer;
- }
- }
- // Copy the merged buffer back into the output, if necessary, and
- // append the rest of the window.
- output_buffer_->MergeBack(kOutputAnalysis,
- output_pointer, output_merge_cnt);
- output_buffer_->Write(input_pointer, remaining_count);
-
- // Advance the output analysis pointer to the next target merge point,
- // minus half an overlap window. The target merge point is always
- // calculated as a delta from the previous ideal target, not the actual
- // target, to avoid drift.
- int output_advance = target_merge_offset_;
- if (output_merge_cnt < half_overlap_frames_) {
- // On the first window, back up the pointer for the next correlation.
- // Thereafter, that compensation is preserved.
- output_advance -= half_overlap_frames_;
- }
-
- // Don't advance beyond the available data, when finishing up.
- if (draining_) {
- output_advance =
- min(output_advance, output_buffer_->available(kOutputAnalysis));
- }
- output_buffer_->Seek(kOutputAnalysis,
- output_buffer_->Tell(kOutputAnalysis) + output_advance);
-
- // Advance the input pointer beyond the frames that are no longer needed.
- input_buffer_->Seek(kInputReader, input_buffer_->Tell(kInputReader) +
- min(input_count, input_window_offset_));
-
- if ((crossfade_count + remaining_count) > 0) {
- generated_data = true;
- }
- } // while (more to process)
- return generated_data;
-}
-
-} // namespace video_editing
diff --git a/variablespeed/jni/sola_time_scaler.h b/variablespeed/jni/sola_time_scaler.h
deleted file mode 100644
index c903f61..0000000
--- a/variablespeed/jni/sola_time_scaler.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef FRAMEWORKS_EX_VARIABLESPEED_JNI_SOLA_TIME_SCALER_H_
-#define FRAMEWORKS_EX_VARIABLESPEED_JNI_SOLA_TIME_SCALER_H_
-
-#include <android/log.h>
-
-#include <no_synchronization.h>
-
-#include <list>
-#include <vector>
-
-#include "macros.h"
-
-// Time-domain audio playback rate scaler using phase-aligned Synchronized
-// OverLap Add (SOLA).
-
-namespace video_editing {
-
-class RingBuffer;
-
-// The default SolaAnalyzer implements a sign-bit cross-correlation
-// function for determining the best fit between two signals.
-class SolaAnalyzer {
- public:
- SolaAnalyzer() : initialized_(false) { }
- virtual ~SolaAnalyzer() { }
-
- // Initializes a SolaAnalyzer.
- // @param sample_rate sample rate of the audio signal.
- // @param num_channels number of interleaved channels in the signal.
- void Init(int sample_rate, int num_channels) {
- sample_rate_ = sample_rate;
- num_channels_ = num_channels;
- initialized_ = true;
- }
-
- // Returns a cross-correlation score for the specified buffers.
- // The correlation is performed over all channels of a multi-channel signal.
- // @param buffer1 pointer to interleaved input samples
- // @param buffer2 pointer to interleaved input samples
- // @param num_frames number of input frames (that is to say, number of
- // samples / number of channels)
- // @param returns a correlation score in the range zero to num_frames
- virtual int Correlate(const float* buffer1, const float* buffer2,
- int num_frames);
-
- protected:
- bool initialized_;
- int sample_rate_;
- int num_channels_;
-
- DISALLOW_COPY_AND_ASSIGN(SolaAnalyzer);
-};
-
-
-class SolaTimeScaler {
- public:
- // Default constructor.
- SolaTimeScaler();
- virtual ~SolaTimeScaler();
-
- // Injects a SolaAnalyzer instance for analyzing signal frames.
- // The scaler takes ownership of this instance.
- // This is normally called once, before Init().
- // @param analyzer SolaAnalyzer instance
- void set_analyzer(SolaAnalyzer* analyzer);
-
- // Initializes a SOLA timescaler.
- // @param sample_rate sample rate of the signal to process
- // @param num_channels number of channels of the signal to process
- // @param initial_speed starting rate scaling factor
- // @param window_duration processing window size, in seconds
- // @param overlap_duration correlation overlap size, in seconds
- void Init(double sample_rate, int num_channels, double initial_speed,
- double window_duration, double overlap_duration);
-
- // Adjusts the rate scaling factor.
- // This may be called concurrently with processing, and will
- // take effect on the next processing window.
- // @param speed rate scaling factor
- void set_speed(double speed);
-
- // Indicates that we are done with the input and won't call Process anymore
- // This processes all the data reamining in the analysis buffer.
- void Drain();
-
- // Flushes the buffers associated with the scaler.
- void Reset();
-
- // Feeds audio to the timescaler, and processes as much data as possible.
- // @param buffer pointer to interleaved float input samples
- // @param num_frames number of frames (num_samples / num_channels)
- // @returns number of frames actually accepted
- int InjectSamples(float* buffer, int num_frames);
-
- // Retrieves audio data from the timescaler.
- // @param buffer pointer to buffer to receive interleaved float output
- // @param num_frames maximum desired number of frames
- // @returns number of frames actually returned
- int RetrieveSamples(float* buffer, int num_frames);
-
- // Returns the number of frames that the input buffer can accept.
- // @returns number of frames for the next Process() call
- int input_limit() const;
-
- // Returns the number of available output frames.
- // @returns number of frames that can be retrieved
- int available();
-
- int num_channels() const { return num_channels_; }
-
- private:
- mutable Mutex mutex_; // allows concurrent produce/consume/param change
- bool initialized_; // set true when input parameters have been set
- bool draining_; // set true to drain latency
-
- // Input parameters.
- int num_channels_; // channel valence of audio stream
- double sample_rate_; // sample rate of audio stream
- double window_duration_; // the nominal time quantum for processing
- double overlap_duration_; // the maximum slip for correlating windows
- double speed_; // varispeed rate
-
- // Derived parameters.
- double ratio_; // inverse of speed
- int num_window_frames_; // window_duration_ expressed as frame count
- int num_overlap_frames_; // overlap_duration_ expressed as frame count
- int half_overlap_frames_; // half of the overlap
- int input_window_offset_; // frame delta between input windows
- int target_merge_offset_; // ideal frame delta between output windows
- int max_frames_to_merge_; // ideal frame count to merge to output
- int min_output_to_hold_; // number of output frames needed for next merge
-
- RingBuffer* input_buffer_;
- RingBuffer* output_buffer_;
- SolaAnalyzer* analyzer_;
-
- // Generates processing parameters from the current settings.
- void GenerateParameters();
-
- // Munges input samples to produce output.
- // @returns true if any output samples were generated
- bool Process();
-
- DISALLOW_COPY_AND_ASSIGN(SolaTimeScaler);
-};
-
-} // namespace video_editing
-
-#endif // FRAMEWORKS_EX_VARIABLESPEED_JNI_SOLA_TIME_SCALER_H_
diff --git a/variablespeed/jni/variablespeed.cc b/variablespeed/jni/variablespeed.cc
deleted file mode 100644
index 8e161fc..0000000
--- a/variablespeed/jni/variablespeed.cc
+++ /dev/null
@@ -1,864 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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 <variablespeed.h>
-
-#include <unistd.h>
-#include <stdlib.h>
-
-#include <sola_time_scaler.h>
-#include <ring_buffer.h>
-
-#include <hlogging.h>
-
-#include <vector>
-
-#include <sys/system_properties.h>
-
-// ****************************************************************************
-// Constants, utility methods, structures and other miscellany used throughout
-// this file.
-
-namespace {
-
-// These variables are used to determine the size of the buffer queue used by
-// the decoder.
-// This is not the same as the large buffer used to hold the uncompressed data
-// - for that see the member variable decodeBuffer_.
-// The choice of 1152 corresponds to the number of samples per mp3 frame, so is
-// a good choice of size for a decoding buffer in the absence of other
-// information (we don't know exactly what formats we will be working with).
-const size_t kNumberOfBuffersInQueue = 4;
-const size_t kNumberOfSamplesPerBuffer = 1152;
-const size_t kBufferSizeInBytes = 2 * kNumberOfSamplesPerBuffer;
-const size_t kSampleSizeInBytes = 4;
-
-// When calculating play buffer size before pushing to audio player.
-const size_t kNumberOfBytesPerInt16 = 2;
-
-// How long to sleep during the main play loop and the decoding callback loop.
-// In due course this should be replaced with the better signal and wait on
-// condition rather than busy-looping.
-const int kSleepTimeMicros = 1000;
-
-// Used in detecting errors with the OpenSL ES framework.
-const SLuint32 kPrefetchErrorCandidate =
- SL_PREFETCHEVENT_STATUSCHANGE | SL_PREFETCHEVENT_FILLLEVELCHANGE;
-
-// Structure used when we perform a decoding callback.
-typedef struct CallbackContext_ {
- // Pointer to local storage buffers for decoded audio data.
- int8_t* pDataBase;
- // Pointer to the current buffer within local storage.
- int8_t* pData;
- // Used to read the sample rate and channels from the decoding stream during
- // the first decoding callback.
- SLMetadataExtractionItf decoderMetadata;
- // The play interface used for reading duration.
- SLPlayItf playItf;
-} CallbackContext;
-
-// Local storage for decoded audio data.
-int8_t pcmData[kNumberOfBuffersInQueue * kBufferSizeInBytes];
-
-#define CheckSLResult(message, result) \
- CheckSLResult_Real(message, result, __LINE__)
-
-// Helper function for debugging - checks the OpenSL result for success.
-void CheckSLResult_Real(const char* message, SLresult result, int line) {
- // This can be helpful when debugging.
- // LOGD("sl result %d for %s", result, message);
- if (SL_RESULT_SUCCESS != result) {
- LOGE("slresult was %d at %s file variablespeed line %d",
- static_cast<int>(result), message, line);
- }
- CHECK(SL_RESULT_SUCCESS == result);
-}
-
-// Whether logging should be enabled. Only used if LOG_OPENSL_API_CALL is
-// defined to use it.
-bool gLogEnabled = false;
-// The property to set in order to enable logging.
-const char *const kLogTagVariableSpeed = "log.tag.VariableSpeed";
-
-bool ShouldLog() {
- char buffer[PROP_VALUE_MAX];
- __system_property_get(kLogTagVariableSpeed, buffer);
- return strlen(buffer) > 0;
-}
-
-} // namespace
-
-// ****************************************************************************
-// Static instance of audio engine, and methods for getting, setting and
-// deleting it.
-
-// The single global audio engine instance.
-AudioEngine* AudioEngine::audioEngine_ = NULL;
-android::Mutex publishEngineLock_;
-
-AudioEngine* AudioEngine::GetEngine() {
- android::Mutex::Autolock autoLock(publishEngineLock_);
- if (audioEngine_ == NULL) {
- LOGE("you haven't initialized the audio engine");
- CHECK(false);
- return NULL;
- }
- return audioEngine_;
-}
-
-void AudioEngine::SetEngine(AudioEngine* engine) {
- if (audioEngine_ != NULL) {
- LOGE("you have already set the audio engine");
- CHECK(false);
- return;
- }
- audioEngine_ = engine;
-}
-
-bool AudioEngine::CompareAndSetEngine(AudioEngine* expect, AudioEngine* update) {
- android::Mutex::Autolock autoLock(publishEngineLock_);
- if (audioEngine_ == expect) {
- DeleteEngine();
- audioEngine_ = update;
- return true;
- }
- return false;
-}
-
-void AudioEngine::DeleteEngine() {
- if (audioEngine_ != NULL) {
- delete audioEngine_;
- audioEngine_ = NULL;
- }
-}
-
-// ****************************************************************************
-// The callbacks from the engine require static callback functions.
-// Here are the static functions - they just delegate to instance methods on
-// the engine.
-
-static void PlayingBufferQueueCb(SLAndroidSimpleBufferQueueItf, void*) {
- AudioEngine::GetEngine()->PlayingBufferQueueCallback();
-}
-
-static void PrefetchEventCb(SLPrefetchStatusItf caller, void*, SLuint32 event) {
- AudioEngine::GetEngine()->PrefetchEventCallback(caller, event);
-}
-
-static void DecodingBufferQueueCb(SLAndroidSimpleBufferQueueItf queueItf,
- void *context) {
- AudioEngine::GetEngine()->DecodingBufferQueueCallback(queueItf, context);
-}
-
-static void DecodingEventCb(SLPlayItf caller, void*, SLuint32 event) {
- AudioEngine::GetEngine()->DecodingEventCallback(caller, event);
-}
-
-// ****************************************************************************
-// Macros for making working with OpenSL easier.
-
-// Log based on the value of a property.
-#define LOG_OPENSL_API_CALL(string) (gLogEnabled && LOGV(string))
-
-// The regular macro: log an api call, make the api call, check the result.
-#define OpenSL(obj, method, ...) \
-{ \
- LOG_OPENSL_API_CALL("OpenSL " #method "(" #obj ", " #__VA_ARGS__ ")"); \
- SLresult result = (*obj)->method(obj, __VA_ARGS__); \
- CheckSLResult("OpenSL " #method "(" #obj ", " #__VA_ARGS__ ")", result); \
-}
-
-// Special case call for api call that has void return value, can't be checked.
-#define VoidOpenSL(obj, method) \
-{ \
- LOG_OPENSL_API_CALL("OpenSL (void) " #method "(" #obj ")"); \
- (*obj)->method(obj); \
-}
-
-// Special case for api call with checked result but takes no arguments.
-#define OpenSL0(obj, method) \
-{ \
- LOG_OPENSL_API_CALL("OpenSL " #method "(" #obj ")"); \
- SLresult result = (*obj)->method(obj); \
- CheckSLResult("OpenSL " #method "(" #obj ")", result); \
-}
-
-// Special case for api call whose result we want to store, not check.
-// We have to encapsulate the two calls in braces, so that this expression
-// evaluates to the last expression not the first.
-#define ReturnOpenSL(obj, method, ...) \
-( \
- LOG_OPENSL_API_CALL("OpenSL (int) " \
- #method "(" #obj ", " #__VA_ARGS__ ")"), \
- (*obj)->method(obj, __VA_ARGS__) \
-) \
-
-// ****************************************************************************
-// Static utility methods.
-
-// Set the audio stream type for the player.
-//
-// Must be called before it is realized.
-//
-// The caller must have requested the SL_IID_ANDROIDCONFIGURATION interface when
-// creating the player.
-static void setAudioStreamType(SLObjectItf audioPlayer, SLint32 audioStreamType) {
- SLAndroidConfigurationItf playerConfig;
- OpenSL(audioPlayer, GetInterface, SL_IID_ANDROIDCONFIGURATION, &playerConfig);
- // The STREAM_XXX constants defined by android.media.AudioManager match the
- // corresponding SL_ANDROID_STREAM_XXX constants defined by
- // include/SLES/OpenSLES_AndroidConfiguration.h, so we can just pass the
- // value across.
- OpenSL(playerConfig, SetConfiguration, SL_ANDROID_KEY_STREAM_TYPE,
- &audioStreamType, sizeof(audioStreamType));
-}
-
-// Must be called with callbackLock_ held.
-static void ReadSampleRateAndChannelCount(CallbackContext *pContext,
- SLuint32 *sampleRateOut, SLuint32 *channelsOut) {
- SLMetadataExtractionItf decoderMetadata = pContext->decoderMetadata;
- SLuint32 itemCount;
- OpenSL(decoderMetadata, GetItemCount, &itemCount);
- SLuint32 i, keySize, valueSize;
- SLMetadataInfo *keyInfo, *value;
- for (i = 0; i < itemCount; ++i) {
- keyInfo = value = NULL;
- keySize = valueSize = 0;
- OpenSL(decoderMetadata, GetKeySize, i, &keySize);
- keyInfo = static_cast<SLMetadataInfo*>(malloc(keySize));
- if (keyInfo) {
- OpenSL(decoderMetadata, GetKey, i, keySize, keyInfo);
- if (keyInfo->encoding == SL_CHARACTERENCODING_ASCII
- || keyInfo->encoding == SL_CHARACTERENCODING_UTF8) {
- OpenSL(decoderMetadata, GetValueSize, i, &valueSize);
- value = static_cast<SLMetadataInfo*>(malloc(valueSize));
- if (value) {
- OpenSL(decoderMetadata, GetValue, i, valueSize, value);
- if (strcmp((char*) keyInfo->data, ANDROID_KEY_PCMFORMAT_SAMPLERATE) == 0) {
- SLuint32 sampleRate = *(reinterpret_cast<SLuint32*>(value->data));
- LOGD("sample Rate: %d", sampleRate);
- *sampleRateOut = sampleRate;
- } else if (strcmp((char*) keyInfo->data, ANDROID_KEY_PCMFORMAT_NUMCHANNELS) == 0) {
- SLuint32 channels = *(reinterpret_cast<SLuint32*>(value->data));
- LOGD("channels: %d", channels);
- *channelsOut = channels;
- }
- free(value);
- }
- }
- free(keyInfo);
- }
- }
-}
-
-// Must be called with callbackLock_ held.
-static void RegisterCallbackContextAndAddEnqueueBuffersToDecoder(
- SLAndroidSimpleBufferQueueItf decoderQueue, CallbackContext* context) {
- // Register a callback on the decoder queue, so that we will be called
- // throughout the decoding process (and can then extract the decoded audio
- // for the next bit of the pipeline).
- OpenSL(decoderQueue, RegisterCallback, DecodingBufferQueueCb, context);
-
- // Enqueue buffers to map the region of memory allocated to store the
- // decoded data.
- for (size_t i = 0; i < kNumberOfBuffersInQueue; i++) {
- OpenSL(decoderQueue, Enqueue, context->pData, kBufferSizeInBytes);
- context->pData += kBufferSizeInBytes;
- }
- context->pData = context->pDataBase;
-}
-
-// ****************************************************************************
-// Constructor and Destructor.
-
-AudioEngine::AudioEngine(size_t targetFrames, float windowDuration,
- float windowOverlapDuration, size_t maxPlayBufferCount, float initialRate,
- size_t decodeInitialSize, size_t decodeMaxSize, size_t startPositionMillis,
- int audioStreamType)
- : decodeBuffer_(decodeInitialSize, decodeMaxSize),
- playingBuffers_(), freeBuffers_(), timeScaler_(NULL),
- floatBuffer_(NULL), injectBuffer_(NULL),
- mSampleRate(0), mChannels(0),
- targetFrames_(targetFrames),
- windowDuration_(windowDuration),
- windowOverlapDuration_(windowOverlapDuration),
- maxPlayBufferCount_(maxPlayBufferCount), initialRate_(initialRate),
- startPositionMillis_(startPositionMillis),
- audioStreamType_(audioStreamType),
- totalDurationMs_(0), decoderCurrentPosition_(0), startRequested_(false),
- stopRequested_(false), finishedDecoding_(false) {
- // Determine whether we should log calls.
- gLogEnabled = ShouldLog();
-}
-
-AudioEngine::~AudioEngine() {
- // destroy the time scaler
- if (timeScaler_ != NULL) {
- delete timeScaler_;
- timeScaler_ = NULL;
- }
-
- // delete all outstanding playing and free buffers
- android::Mutex::Autolock autoLock(playBufferLock_);
- while (playingBuffers_.size() > 0) {
- delete[] playingBuffers_.front();
- playingBuffers_.pop();
- }
- while (freeBuffers_.size() > 0) {
- delete[] freeBuffers_.top();
- freeBuffers_.pop();
- }
-
- delete[] floatBuffer_;
- floatBuffer_ = NULL;
- delete[] injectBuffer_;
- injectBuffer_ = NULL;
-}
-
-// ****************************************************************************
-// Regular AudioEngine class methods.
-
-void AudioEngine::SetVariableSpeed(float speed) {
- // TODO: Mutex for shared time scaler accesses.
- if (HasSampleRateAndChannels()) {
- GetTimeScaler()->set_speed(speed);
- } else {
- // This is being called at a point where we have not yet processed enough
- // data to determine the sample rate and number of channels.
- // Ignore the call. See http://b/5140693.
- LOGD("set varaible speed called, sample rate and channels not ready yet");
- }
-}
-
-void AudioEngine::RequestStart() {
- android::Mutex::Autolock autoLock(lock_);
- startRequested_ = true;
-}
-
-void AudioEngine::ClearRequestStart() {
- android::Mutex::Autolock autoLock(lock_);
- startRequested_ = false;
-}
-
-bool AudioEngine::GetWasStartRequested() {
- android::Mutex::Autolock autoLock(lock_);
- return startRequested_;
-}
-
-void AudioEngine::RequestStop() {
- android::Mutex::Autolock autoLock(lock_);
- stopRequested_ = true;
-}
-
-int AudioEngine::GetCurrentPosition() {
- android::Mutex::Autolock autoLock(decodeBufferLock_);
- double result = decodeBuffer_.GetTotalAdvancedCount();
- // TODO: This is horrible, but should be removed soon once the outstanding
- // issue with get current position on decoder is fixed.
- android::Mutex::Autolock autoLock2(callbackLock_);
- return static_cast<int>(
- (result * 1000) / mSampleRate / mChannels + startPositionMillis_);
-}
-
-int AudioEngine::GetTotalDuration() {
- android::Mutex::Autolock autoLock(lock_);
- return static_cast<int>(totalDurationMs_);
-}
-
-video_editing::SolaTimeScaler* AudioEngine::GetTimeScaler() {
- if (timeScaler_ == NULL) {
- CHECK(HasSampleRateAndChannels());
- android::Mutex::Autolock autoLock(callbackLock_);
- timeScaler_ = new video_editing::SolaTimeScaler();
- timeScaler_->Init(mSampleRate, mChannels, initialRate_, windowDuration_,
- windowOverlapDuration_);
- }
- return timeScaler_;
-}
-
-bool AudioEngine::EnqueueNextBufferOfAudio(
- SLAndroidSimpleBufferQueueItf audioPlayerQueue) {
- size_t channels;
- {
- android::Mutex::Autolock autoLock(callbackLock_);
- channels = mChannels;
- }
- size_t frameSizeInBytes = kSampleSizeInBytes * channels;
- size_t frameCount = 0;
- while (frameCount < targetFrames_) {
- size_t framesLeft = targetFrames_ - frameCount;
- // If there is data already in the time scaler, retrieve it.
- if (GetTimeScaler()->available() > 0) {
- size_t retrieveCount = min(GetTimeScaler()->available(), framesLeft);
- int count = GetTimeScaler()->RetrieveSamples(
- floatBuffer_ + frameCount * channels, retrieveCount);
- if (count <= 0) {
- LOGD("error: count was %d", count);
- break;
- }
- frameCount += count;
- continue;
- }
- // If there is no data in the time scaler, then feed some into it.
- android::Mutex::Autolock autoLock(decodeBufferLock_);
- size_t framesInDecodeBuffer =
- decodeBuffer_.GetSizeInBytes() / frameSizeInBytes;
- size_t framesScalerCanHandle = GetTimeScaler()->input_limit();
- size_t framesToInject = min(framesInDecodeBuffer,
- min(targetFrames_, framesScalerCanHandle));
- if (framesToInject <= 0) {
- // No more frames left to inject.
- break;
- }
- for (size_t i = 0; i < framesToInject * channels; ++i) {
- injectBuffer_[i] = decodeBuffer_.GetAtIndex(i);
- }
- int count = GetTimeScaler()->InjectSamples(injectBuffer_, framesToInject);
- if (count <= 0) {
- LOGD("error: count was %d", count);
- break;
- }
- decodeBuffer_.AdvanceHeadPointerShorts(count * channels);
- }
- if (frameCount <= 0) {
- // We must have finished playback.
- if (GetEndOfDecoderReached()) {
- // If we've finished decoding, clear the buffer - so we will terminate.
- ClearDecodeBuffer();
- }
- return false;
- }
-
- // Get a free playing buffer.
- int16* playBuffer;
- {
- android::Mutex::Autolock autoLock(playBufferLock_);
- if (freeBuffers_.size() > 0) {
- // If we have a free buffer, recycle it.
- playBuffer = freeBuffers_.top();
- freeBuffers_.pop();
- } else {
- // Otherwise allocate a new one.
- playBuffer = new int16[targetFrames_ * channels];
- }
- }
-
- // Try to play the buffer.
- for (size_t i = 0; i < frameCount * channels; ++i) {
- playBuffer[i] = floatBuffer_[i];
- }
- size_t sizeOfPlayBufferInBytes =
- frameCount * channels * kNumberOfBytesPerInt16;
- SLresult result = ReturnOpenSL(audioPlayerQueue, Enqueue, playBuffer,
- sizeOfPlayBufferInBytes);
- if (result == SL_RESULT_SUCCESS) {
- android::Mutex::Autolock autoLock(playBufferLock_);
- playingBuffers_.push(playBuffer);
- } else {
- LOGE("could not enqueue audio buffer");
- delete[] playBuffer;
- }
-
- return (result == SL_RESULT_SUCCESS);
-}
-
-bool AudioEngine::GetEndOfDecoderReached() {
- android::Mutex::Autolock autoLock(lock_);
- return finishedDecoding_;
-}
-
-void AudioEngine::SetEndOfDecoderReached() {
- android::Mutex::Autolock autoLock(lock_);
- finishedDecoding_ = true;
-}
-
-bool AudioEngine::PlayFileDescriptor(int fd, int64 offset, int64 length) {
- SLDataLocator_AndroidFD loc_fd = {
- SL_DATALOCATOR_ANDROIDFD, fd, offset, length };
- SLDataFormat_MIME format_mime = {
- SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED };
- SLDataSource audioSrc = { &loc_fd, &format_mime };
- return PlayFromThisSource(audioSrc);
-}
-
-bool AudioEngine::PlayUri(const char* uri) {
- // Source of audio data for the decoding
- SLDataLocator_URI decUri = { SL_DATALOCATOR_URI,
- const_cast<SLchar*>(reinterpret_cast<const SLchar*>(uri)) };
- SLDataFormat_MIME decMime = {
- SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED };
- SLDataSource decSource = { &decUri, &decMime };
- return PlayFromThisSource(decSource);
-}
-
-bool AudioEngine::IsDecodeBufferEmpty() {
- android::Mutex::Autolock autoLock(decodeBufferLock_);
- return decodeBuffer_.GetSizeInBytes() <= 0;
-}
-
-void AudioEngine::ClearDecodeBuffer() {
- android::Mutex::Autolock autoLock(decodeBufferLock_);
- decodeBuffer_.Clear();
-}
-
-static size_t ReadDuration(SLPlayItf playItf) {
- SLmillisecond durationInMsec = SL_TIME_UNKNOWN;
- OpenSL(playItf, GetDuration, &durationInMsec);
- if (durationInMsec == SL_TIME_UNKNOWN) {
- LOGE("can't get duration");
- return 0;
- }
- LOGD("duration: %d", static_cast<int>(durationInMsec));
- return durationInMsec;
-}
-
-static size_t ReadPosition(SLPlayItf playItf) {
- SLmillisecond positionInMsec = SL_TIME_UNKNOWN;
- OpenSL(playItf, GetPosition, &positionInMsec);
- if (positionInMsec == SL_TIME_UNKNOWN) {
- LOGE("can't get position");
- return 0;
- }
- LOGW("decoder position: %d", static_cast<int>(positionInMsec));
- return positionInMsec;
-}
-
-static void CreateAndRealizeEngine(SLObjectItf &engine,
- SLEngineItf &engineInterface) {
- SLEngineOption EngineOption[] = { {
- SL_ENGINEOPTION_THREADSAFE, SL_BOOLEAN_TRUE } };
- SLresult result = slCreateEngine(&engine, 1, EngineOption, 0, NULL, NULL);
- CheckSLResult("create engine", result);
- OpenSL(engine, Realize, SL_BOOLEAN_FALSE);
- OpenSL(engine, GetInterface, SL_IID_ENGINE, &engineInterface);
-}
-
-SLuint32 AudioEngine::GetSLSampleRate() {
- android::Mutex::Autolock autoLock(callbackLock_);
- return mSampleRate * 1000;
-}
-
-SLuint32 AudioEngine::GetSLChannels() {
- android::Mutex::Autolock autoLock(callbackLock_);
- switch (mChannels) {
- case 2:
- return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
- case 1:
- return SL_SPEAKER_FRONT_CENTER;
- default:
- LOGE("unknown channels %d, using 2", mChannels);
- return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
- }
-}
-
-SLuint32 AudioEngine::GetChannelCount() {
- android::Mutex::Autolock autoLock(callbackLock_);
- return mChannels;
-}
-
-static void CreateAndRealizeAudioPlayer(SLuint32 slSampleRate,
- SLuint32 channelCount, SLuint32 slChannels, SLint32 audioStreamType, SLObjectItf &outputMix,
- SLObjectItf &audioPlayer, SLEngineItf &engineInterface) {
- // Define the source and sink for the audio player: comes from a buffer queue
- // and goes to the output mix.
- SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
- SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2 };
- SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM, channelCount, slSampleRate,
- SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
- slChannels, SL_BYTEORDER_LITTLEENDIAN};
- SLDataSource playingSrc = {&loc_bufq, &format_pcm};
- SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMix};
- SLDataSink audioSnk = {&loc_outmix, NULL};
-
- // Create the audio player, which will play from the buffer queue and send to
- // the output mix.
- const size_t playerInterfaceCount = 2;
- const SLInterfaceID iids[playerInterfaceCount] = {
- SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION };
- const SLboolean reqs[playerInterfaceCount] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
- OpenSL(engineInterface, CreateAudioPlayer, &audioPlayer, &playingSrc,
- &audioSnk, playerInterfaceCount, iids, reqs);
- setAudioStreamType(audioPlayer, audioStreamType);
- OpenSL(audioPlayer, Realize, SL_BOOLEAN_FALSE);
-}
-
-bool AudioEngine::HasSampleRateAndChannels() {
- android::Mutex::Autolock autoLock(callbackLock_);
- return mChannels != 0 && mSampleRate != 0;
-}
-
-bool AudioEngine::PlayFromThisSource(const SLDataSource& audioSrc) {
- ClearDecodeBuffer();
-
- SLObjectItf engine;
- SLEngineItf engineInterface;
- CreateAndRealizeEngine(engine, engineInterface);
-
- // Define the source and sink for the decoding player: comes from the source
- // this method was called with, is sent to another buffer queue.
- SLDataLocator_AndroidSimpleBufferQueue decBuffQueue;
- decBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
- decBuffQueue.numBuffers = kNumberOfBuffersInQueue;
- // A valid value seems required here but is currently ignored.
- SLDataFormat_PCM pcm = {SL_DATAFORMAT_PCM, 1, SL_SAMPLINGRATE_44_1,
- SL_PCMSAMPLEFORMAT_FIXED_16, 16,
- SL_SPEAKER_FRONT_LEFT, SL_BYTEORDER_LITTLEENDIAN};
- SLDataSink decDest = { &decBuffQueue, &pcm };
-
- // Create the decoder with the given source and sink.
- const size_t decoderInterfaceCount = 5;
- SLObjectItf decoder;
- const SLInterfaceID decodePlayerInterfaces[decoderInterfaceCount] = {
- SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_PREFETCHSTATUS, SL_IID_SEEK,
- SL_IID_METADATAEXTRACTION, SL_IID_ANDROIDCONFIGURATION };
- const SLboolean decodePlayerRequired[decoderInterfaceCount] = {
- SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
- SLDataSource sourceCopy(audioSrc);
- OpenSL(engineInterface, CreateAudioPlayer, &decoder, &sourceCopy, &decDest,
- decoderInterfaceCount, decodePlayerInterfaces, decodePlayerRequired);
- // Not sure if this is necessary, but just in case.
- setAudioStreamType(decoder, audioStreamType_);
- OpenSL(decoder, Realize, SL_BOOLEAN_FALSE);
-
- // Get the play interface from the decoder, and register event callbacks.
- // Get the buffer queue, prefetch and seek interfaces.
- SLPlayItf decoderPlay = NULL;
- SLAndroidSimpleBufferQueueItf decoderQueue = NULL;
- SLPrefetchStatusItf decoderPrefetch = NULL;
- SLSeekItf decoderSeek = NULL;
- SLMetadataExtractionItf decoderMetadata = NULL;
- OpenSL(decoder, GetInterface, SL_IID_PLAY, &decoderPlay);
- OpenSL(decoderPlay, SetCallbackEventsMask, SL_PLAYEVENT_HEADATEND);
- OpenSL(decoderPlay, RegisterCallback, DecodingEventCb, NULL);
- OpenSL(decoder, GetInterface, SL_IID_PREFETCHSTATUS, &decoderPrefetch);
- OpenSL(decoder, GetInterface, SL_IID_SEEK, &decoderSeek);
- OpenSL(decoder, GetInterface, SL_IID_METADATAEXTRACTION, &decoderMetadata);
- OpenSL(decoder, GetInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
- &decoderQueue);
-
- // Initialize the callback structure, used during the decoding.
- CallbackContext callbackContext;
- {
- android::Mutex::Autolock autoLock(callbackLock_);
- callbackContext.pDataBase = pcmData;
- callbackContext.pData = pcmData;
- callbackContext.decoderMetadata = decoderMetadata;
- callbackContext.playItf = decoderPlay;
- RegisterCallbackContextAndAddEnqueueBuffersToDecoder(
- decoderQueue, &callbackContext);
- }
-
- // Initialize the callback for prefetch errors, if we can't open the
- // resource to decode.
- OpenSL(decoderPrefetch, SetCallbackEventsMask, kPrefetchErrorCandidate);
- OpenSL(decoderPrefetch, RegisterCallback, PrefetchEventCb, &decoderPrefetch);
-
- // Seek to the start position.
- OpenSL(decoderSeek, SetPosition, startPositionMillis_, SL_SEEKMODE_ACCURATE);
-
- // Start decoding immediately.
- OpenSL(decoderPlay, SetPlayState, SL_PLAYSTATE_PLAYING);
-
- // These variables hold the audio player and its output.
- // They will only be constructed once the decoder has invoked the callback,
- // and given us the correct sample rate, number of channels and duration.
- SLObjectItf outputMix = NULL;
- SLObjectItf audioPlayer = NULL;
- SLPlayItf audioPlayerPlay = NULL;
- SLAndroidSimpleBufferQueueItf audioPlayerQueue = NULL;
-
- // The main loop - until we're told to stop: if there is audio data coming
- // out of the decoder, feed it through the time scaler.
- // As it comes out of the time scaler, feed it into the audio player.
- while (!Finished()) {
- if (GetWasStartRequested() && HasSampleRateAndChannels()) {
- // Build the audio player.
- // TODO: What happens if I maliciously call start lots of times?
- floatBuffer_ = new float[targetFrames_ * mChannels];
- injectBuffer_ = new float[targetFrames_ * mChannels];
- OpenSL(engineInterface, CreateOutputMix, &outputMix, 0, NULL, NULL);
- OpenSL(outputMix, Realize, SL_BOOLEAN_FALSE);
- CreateAndRealizeAudioPlayer(GetSLSampleRate(), GetChannelCount(),
- GetSLChannels(), audioStreamType_, outputMix, audioPlayer,
- engineInterface);
- OpenSL(audioPlayer, GetInterface, SL_IID_PLAY, &audioPlayerPlay);
- OpenSL(audioPlayer, GetInterface, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
- &audioPlayerQueue);
- OpenSL(audioPlayerQueue, RegisterCallback, PlayingBufferQueueCb, NULL);
- ClearRequestStart();
- OpenSL(audioPlayerPlay, SetPlayState, SL_PLAYSTATE_PLAYING);
- }
- EnqueueMoreAudioIfNecessary(audioPlayerQueue);
- usleep(kSleepTimeMicros);
- }
-
- // Delete the audio player and output mix, iff they have been created.
- if (audioPlayer != NULL) {
- OpenSL(audioPlayerPlay, SetPlayState, SL_PLAYSTATE_STOPPED);
- OpenSL0(audioPlayerQueue, Clear);
- OpenSL(audioPlayerQueue, RegisterCallback, NULL, NULL);
- VoidOpenSL(audioPlayer, AbortAsyncOperation);
- VoidOpenSL(audioPlayer, Destroy);
- VoidOpenSL(outputMix, Destroy);
- audioPlayer = NULL;
- audioPlayerPlay = NULL;
- audioPlayerQueue = NULL;
- outputMix = NULL;
- }
-
- // Delete the decoder.
- OpenSL(decoderPlay, SetPlayState, SL_PLAYSTATE_STOPPED);
- OpenSL(decoderPrefetch, RegisterCallback, NULL, NULL);
- // This is returning slresult 13 if I do no playback.
- // Repro is to comment out all before this line, and all after enqueueing
- // my buffers.
- // OpenSL0(decoderQueue, Clear);
- OpenSL(decoderQueue, RegisterCallback, NULL, NULL);
- decoderSeek = NULL;
- decoderPrefetch = NULL;
- decoderQueue = NULL;
- OpenSL(decoderPlay, RegisterCallback, NULL, NULL);
- VoidOpenSL(decoder, AbortAsyncOperation);
- VoidOpenSL(decoder, Destroy);
- decoderPlay = NULL;
-
- // Delete the engine.
- VoidOpenSL(engine, Destroy);
- engineInterface = NULL;
-
- return true;
-}
-
-bool AudioEngine::Finished() {
- if (GetWasStopRequested()) {
- return true;
- }
- android::Mutex::Autolock autoLock(playBufferLock_);
- return playingBuffers_.size() <= 0 &&
- IsDecodeBufferEmpty() &&
- GetEndOfDecoderReached();
-}
-
-bool AudioEngine::GetWasStopRequested() {
- android::Mutex::Autolock autoLock(lock_);
- return stopRequested_;
-}
-
-bool AudioEngine::GetHasReachedPlayingBuffersLimit() {
- android::Mutex::Autolock autoLock(playBufferLock_);
- return playingBuffers_.size() >= maxPlayBufferCount_;
-}
-
-void AudioEngine::EnqueueMoreAudioIfNecessary(
- SLAndroidSimpleBufferQueueItf audioPlayerQueue) {
- bool keepEnqueueing = true;
- while (audioPlayerQueue != NULL &&
- !GetWasStopRequested() &&
- !IsDecodeBufferEmpty() &&
- !GetHasReachedPlayingBuffersLimit() &&
- keepEnqueueing) {
- keepEnqueueing = EnqueueNextBufferOfAudio(audioPlayerQueue);
- }
-}
-
-bool AudioEngine::DecodeBufferTooFull() {
- android::Mutex::Autolock autoLock(decodeBufferLock_);
- return decodeBuffer_.IsTooLarge();
-}
-
-// ****************************************************************************
-// Code for handling the static callbacks.
-
-void AudioEngine::PlayingBufferQueueCallback() {
- // The head playing buffer is done, move it to the free list.
- android::Mutex::Autolock autoLock(playBufferLock_);
- if (playingBuffers_.size() > 0) {
- freeBuffers_.push(playingBuffers_.front());
- playingBuffers_.pop();
- }
-}
-
-void AudioEngine::PrefetchEventCallback(
- SLPrefetchStatusItf caller, SLuint32 event) {
- // If there was a problem during decoding, then signal the end.
- SLpermille level = 0;
- SLuint32 status;
- OpenSL(caller, GetFillLevel, &level);
- OpenSL(caller, GetPrefetchStatus, &status);
- if ((kPrefetchErrorCandidate == (event & kPrefetchErrorCandidate)) &&
- (level == 0) &&
- (status == SL_PREFETCHSTATUS_UNDERFLOW)) {
- LOGI("prefetcheventcallback error while prefetching data");
- SetEndOfDecoderReached();
- }
- if (SL_PREFETCHSTATUS_SUFFICIENTDATA == event) {
- // android::Mutex::Autolock autoLock(prefetchLock_);
- // prefetchCondition_.broadcast();
- }
-}
-
-void AudioEngine::DecodingBufferQueueCallback(
- SLAndroidSimpleBufferQueueItf queueItf, void *context) {
- if (GetWasStopRequested()) {
- return;
- }
-
- CallbackContext *pCntxt;
- {
- android::Mutex::Autolock autoLock(callbackLock_);
- pCntxt = reinterpret_cast<CallbackContext*>(context);
- }
- {
- android::Mutex::Autolock autoLock(decodeBufferLock_);
- decodeBuffer_.AddData(pCntxt->pData, kBufferSizeInBytes);
- }
-
- if (!HasSampleRateAndChannels()) {
- android::Mutex::Autolock autoLock(callbackLock_);
- ReadSampleRateAndChannelCount(pCntxt, &mSampleRate, &mChannels);
- }
-
- {
- android::Mutex::Autolock autoLock(lock_);
- if (totalDurationMs_ == 0) {
- totalDurationMs_ = ReadDuration(pCntxt->playItf);
- }
- // TODO: This isn't working, it always reports zero.
- // ReadPosition(pCntxt->playItf);
- }
-
- OpenSL(queueItf, Enqueue, pCntxt->pData, kBufferSizeInBytes);
-
- // Increase data pointer by buffer size
- pCntxt->pData += kBufferSizeInBytes;
- if (pCntxt->pData >= pCntxt->pDataBase +
- (kNumberOfBuffersInQueue * kBufferSizeInBytes)) {
- pCntxt->pData = pCntxt->pDataBase;
- }
-
- // If we get too much data into the decoder,
- // sleep until the playback catches up.
- while (!GetWasStopRequested() && DecodeBufferTooFull()) {
- usleep(kSleepTimeMicros);
- }
-}
-
-void AudioEngine::DecodingEventCallback(SLPlayItf, SLuint32 event) {
- if (SL_PLAYEVENT_HEADATEND & event) {
- SetEndOfDecoderReached();
- }
-}
diff --git a/variablespeed/jni/variablespeed.h b/variablespeed/jni/variablespeed.h
deleted file mode 100644
index 74710e5..0000000
--- a/variablespeed/jni/variablespeed.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#ifndef FRAMEWORKS_EX_VARIABLESPEED_JNI_VARIABLESPEED_H_
-#define FRAMEWORKS_EX_VARIABLESPEED_JNI_VARIABLESPEED_H_
-
-#include <jni.h>
-
-#include <SLES/OpenSLES.h>
-#include <SLES/OpenSLES_Android.h>
-#include <SLES/OpenSLES_AndroidConfiguration.h>
-
-#include <integral_types.h>
-#include <utils/threads.h>
-
-#include <profile_timer.h>
-#include <decode_buffer.h>
-
-#include <queue>
-#include <stack>
-
-namespace video_editing {
- class SolaTimeScaler;
-}
-
-// This is the audio engine class.
-// It forms the bulk of the variablespeed library.
-// It should not be used directly, but rather used indirectly from the java
-// native methods.
-class AudioEngine {
- public:
- AudioEngine(size_t targetFrames, float windowDuration,
- float windowOverlapDuration, size_t maxPlayBufferCount,
- float initialRate, size_t decodeInitialSize, size_t decodeMaxSize,
- size_t startPositionMillis, int audioStreamType);
- virtual ~AudioEngine();
-
- bool PlayUri(const char* uri);
- bool PlayFileDescriptor(int fd, int64 offset, int64 length);
- void SetVariableSpeed(float speed);
- void RequestStart();
- void RequestStop();
- int GetCurrentPosition();
- int GetTotalDuration();
-
- void DecodingBufferQueueCallback(
- SLAndroidSimpleBufferQueueItf queueItf, void *context);
- void DecodingEventCallback(SLPlayItf caller, SLuint32 event);
- void PrefetchEventCallback(SLPrefetchStatusItf caller, SLuint32 event);
- void PlayingBufferQueueCallback();
-
- static AudioEngine* GetEngine();
- static void SetEngine(AudioEngine* engine);
- static bool CompareAndSetEngine(AudioEngine* expect, AudioEngine* update);
- static void DeleteEngine();
-
- private:
- bool PlayFromThisSource(const SLDataSource& audioSrc);
- void EnqueueMoreAudioIfNecessary(SLAndroidSimpleBufferQueueItf bufferQueue);
- bool EnqueueNextBufferOfAudio(SLAndroidSimpleBufferQueueItf bufferQueue);
- void PrefetchDurationSampleRateAndChannels(
- SLPlayItf playItf, SLPrefetchStatusItf prefetchItf);
- video_editing::SolaTimeScaler* GetTimeScaler();
- bool Finished();
- bool GetWasStartRequested();
- bool GetWasStopRequested();
- void ClearRequestStart();
- void SetEndOfDecoderReached();
- bool GetEndOfDecoderReached();
- bool DecodeBufferTooFull();
- void ClearDecodeBuffer();
- bool IsDecodeBufferEmpty();
- bool GetHasReachedPlayingBuffersLimit();
- bool HasSampleRateAndChannels();
- SLuint32 GetSLSampleRate();
- SLuint32 GetSLChannels();
- SLuint32 GetChannelCount();
-
- // The single global audio engine instance.
- static AudioEngine* audioEngine_;
-
- // Protects access to the shared decode buffer.
- android::Mutex decodeBufferLock_;
- // Buffer into which we put the audio data as we decode.
- // Protected by decodeBufferLock_.
- DecodeBuffer decodeBuffer_;
-
- // Protects access to the playingBuffers_ and freeBuffers_.
- android::Mutex playBufferLock_;
- // The buffers we're using for playback.
- std::queue<int16*> playingBuffers_;
- std::stack<int16*> freeBuffers_;
-
- // The time scaler.
- video_editing::SolaTimeScaler* timeScaler_;
-
- // The frame buffer, used for converting between PCM data and float for
- // time scaler.
- float* floatBuffer_;
- float* injectBuffer_;
-
- // Required when we create the audio player.
- // Set during the first callback from the decoder.
- // Guarded by callbackLock_.
- SLuint32 mSampleRate;
- SLuint32 mChannels;
-
- size_t targetFrames_;
- float windowDuration_;
- float windowOverlapDuration_;
- size_t maxPlayBufferCount_;
- float initialRate_;
- size_t startPositionMillis_;
- // The type of audio stream as defined by the STREAM_XXX constants in
- // android.media.AudioManager. These constant values actually match the
- // corresponding SL_ANDROID_STREAM_XXX constants defined by
- // include/SLES/OpenSLES_AndroidConfiguration.h
- int audioStreamType_;
-
- // The prefetch callback signal, for letting the prefetch callback method
- // indicate when it is done.
- android::Mutex prefetchLock_;
- android::Condition prefetchCondition_;
-
- // Protects access to the CallbackContext object.
- // I don't believe this to be necessary, I think that it's thread-confined,
- // but it also won't do any harm.
- android::Mutex callbackLock_;
-
- // Protects access to the shared member variables below.
- android::Mutex lock_;
- // Protected by lock_.
- // Stores the total duration of the track.
- SLmillisecond totalDurationMs_;
- // Protected by lock_.
- // Stores the current position of the decoder head.
- SLmillisecond decoderCurrentPosition_;
- // Protected by lock_.
- // Set externally via RequestStart(), this determines when we begin to
- // playback audio.
- // Until this is set to true, our audio player will remain stopped.
- bool startRequested_;
- // Protected by lock_.
- // Set externally via RequestStop(), this tells us top stop playing
- // and therefore shut everything down.
- bool stopRequested_;
- // Protected by lock_.
- // This is set to true once we reach the end of the decoder stream.
- bool finishedDecoding_;
-
- DISALLOW_COPY_AND_ASSIGN(AudioEngine);
-};
-
-#endif // FRAMEWORKS_EX_VARIABLESPEED_JNI_VARIABLESPEED_H_