Files
platform-external-webrtc/webrtc/tools/update_resources.py
turaj@webrtc.org a6101d76f4 Update sampling rate and number of channels of NetEq4 if decoder is changed.
We encounter a sample-underrun if NetEq is initialized with a sampling rate fs =16000 and receive Opus packets with frame-size less than 5 ms. The reason is as follows.

Let say NetEq buffer has 4 packets of Opus each of size 2.5ms this means that internally timestamp of packets incremented by 80 (internally Opus treated as 32 kHz codec). Given the initial sampling rate of NetEq, at the first time that it wants to fetch packets, it targets to fetch 160 samples. Therefore, it will only extracts 2 packets. Decoding these packets give us exactly 160 samples (5 ms at 32 kHz), however, upon decoding the first packet the internal sampling rate will be updated to 32 kHz. So it is expected that sync buffer to deliver 320 samples while it does only have 160 samples (or maybe few more as it starts with some zeros). And we encounter and under-run.

Even if we ignore the under-run  "assert(sync_buffer_->FutureLength() >= expand_->overlap_length())" (neteq_impl.cc::811) is trigered. I'm not sure what happens if we remove this assert perhaps NetEq will work fine in subsequent calls. However the first under-run is blocking ACM2 test to pass.

Here I have a solution to update sample rate as soon as a packet is inserted, if required. It not a very efficient approach as we do the same reset in NetEqImpl::Decode().

It is a bit tricky to reproduce this because the TOT ACM tests do not run ACM2. In https://webrtc-codereview.appspot.com/2192005/ I have a patch to run both ACMs. To reproduce the problem, one can patch that CL and run

$ out/Debug/modules_tests --gtest_filter=AudioCodingModuleTest.TestOpus

Note that we would not encounter any problem if NetEq4 is initiated with 32000 Hz sampling rate. You can test this by setting |kNeteqInitSampleRateHz| to 32000 in webrtc/modules/audio_coding/main/acm2/acm_receiver.cc

BUG=
R=andrew@webrtc.org, henrik.lundin@webrtc.org, kjellander@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/2306004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@4896 4adac7df-926f-26a2-2b94-8c16560cd09d
2013-10-01 22:01:09 +00:00

156 lines
5.6 KiB
Python
Executable File

#!/usr/bin/env python
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
"""Downloads WebRTC resources files from a remote host."""
from optparse import OptionParser
from urlparse import urljoin
import os
import shutil
import sys
import tarfile
import tempfile
import urllib2
DESIRED_VERSION = 17
REMOTE_URL_BASE = 'http://commondatastorage.googleapis.com/webrtc-resources'
VERSION_FILENAME = 'webrtc-resources-version'
FILENAME_PREFIX = 'webrtc-resources-'
EXTENSION = '.tgz'
RELATIVE_OUTPUT_PATH = '../../'
def main():
"""
Downloads WebRTC resources files from a remote host.
This script will download WebRTC resource files used for testing, like audio
and video files. It will check the current version in the DEPS file and
compare it with the one downloaded (kept in a text file in the download dir).
If the DEPS version is different than the one downloaded, the correct version
will be downloaded.
"""
# Make it possible to skip download using an environment variable:
if os.getenv('WEBRTC_SKIP_RESOURCES_DOWNLOAD'):
print 'Skipping resources download since WEBRTC_SKIP_RESOURCES_DOWNLOAD set'
return
# Define and parse arguments.
parser = OptionParser()
parser.add_option('-f', '--force', action='store_true', dest='force',
help='forces download and removal of existing resources.')
parser.add_option('-b', '--base_url', dest='base_url',
help= 'Overrides the default Base URL (%s) and uses the '
'supplied URL instead.' % REMOTE_URL_BASE)
parser.add_option('-p', dest='path', help= 'path of resources directory'
'relative to this script', default=RELATIVE_OUTPUT_PATH)
options = parser.parse_args()[0]
project_root_dir = os.path.normpath(sys.path[0] + '/' + options.path)
downloads_dir = os.path.join(project_root_dir, 'resources')
current_version_file = os.path.join(downloads_dir, VERSION_FILENAME)
# Ensure the downloads dir is created.
if not os.path.isdir(downloads_dir):
os.mkdir(downloads_dir)
# Download archive if forced or DEPS version is different than our current.
current_version = _get_current_version(current_version_file)
if DESIRED_VERSION != current_version or options.force:
base_url = options.base_url or REMOTE_URL_BASE
_perform_download(base_url, DESIRED_VERSION, downloads_dir)
else:
print 'Already have correct version: %s' % current_version
def _get_current_version(current_version_file):
"""Returns the version already downloaded (if any).
Args:
current_version_file: The filename of the text file containing the
currently downloaded version (if any) on local disk.
Returns:
The version number, or 0 if no downloaded version exists.
"""
current_version = 0
if os.path.isfile(current_version_file):
f = open(current_version_file)
current_version = int(f.read())
f.close()
print 'Found downloaded resources: version: %s' % current_version
return current_version
def _perform_download(base_url, desired_version, downloads_dir):
"""Performs the download and extracts the downloaded resources.
Args:
base_url: URL that holds the resource downloads.
desired_version: Desired version, which decides the filename.
"""
temp_dir = tempfile.mkdtemp(prefix='webrtc-resources-')
try:
archive_name = '%s%s%s' % (FILENAME_PREFIX, desired_version, EXTENSION)
# urljoin requires base URL to end with slash to construct a proper URL
# to our file:
if not base_url[-1:] == '/':
base_url += '/'
remote_archive_url = urljoin(base_url, archive_name)
# Download into the temporary directory with display of progress, inspired
# by the Stack Overflow post at http://goo.gl/JIrbo
temp_filename = os.path.join(temp_dir, archive_name)
print 'Downloading: %s' % remote_archive_url
response = urllib2.urlopen(remote_archive_url)
temp_file = open(temp_filename, 'wb')
meta = response.info()
file_size_kb = int(meta.getheaders('Content-Length')[0]) / 1024
print 'Progress: %s : %s kB' % (archive_name, file_size_kb)
file_size_dl_kb = 0
block_size = 65536
while True:
file_buffer = response.read(block_size)
if not file_buffer:
break
file_size_dl_kb += len(file_buffer) / 1024
temp_file.write(file_buffer)
status = r'%10d kB [%3.2f%%]' % (file_size_dl_kb,
file_size_dl_kb * 100. / file_size_kb)
status += chr(8) * (len(status) + 1)
print status,
print
temp_file.close()
# Clean up the existing resources dir.
print 'Removing old resources in %s' % downloads_dir
shutil.rmtree(downloads_dir)
os.mkdir(downloads_dir)
# Extract the archive.
archive = tarfile.open(temp_filename, 'r:gz')
archive.extractall(downloads_dir)
archive.close()
print 'Extracted resource files into %s' % downloads_dir
# Write the downloaded version to a text file in the resources dir to avoid
# re-download of the same version in the future.
new_version_filename = os.path.join(downloads_dir, VERSION_FILENAME)
version_file = open(new_version_filename, 'w')
version_file.write('%d' % desired_version)
version_file.close()
finally:
# Clean up the temp dir.
shutil.rmtree(temp_dir)
if __name__ == '__main__':
main()