pax_global_header00006660000000000000000000000064111270507020014505gustar00rootroot0000000000000052 comment=8efc46814fc3e950e10a1ed0c837a8728b6ec7d0 libcmtspeechdata-2.1.1+git20160721~8efc468/000077500000000000000000000000001112705070200176125ustar00rootroot00000000000000libcmtspeechdata-2.1.1+git20160721~8efc468/COPYING000066400000000000000000000634631112705070200206610ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libcmtspeechdata-2.1.1+git20160721~8efc468/Makefile.am000066400000000000000000000061221112705070200216470ustar00rootroot00000000000000# Copyright (C) 2008,2009,2010 Nokia Corporation # Contact: Kai Vehmanen # Licensed under LGPL. See file COPYING. SUBDIRS = doc \ dummy-backend EXTRA_DIST = cmtspeech_config.h.in \ libcmtspeechdata.ver # libcmtspeechdata main library sources # ------------------------------------- lib_LTLIBRARIES = libcmtspeechdata.la nokiamodem_src = cmtspeech_msgs.c \ cmtspeech_nokiamodem.c \ cmtspeech_backend_common.c nokiamodem_kernel_inc = \ kernel-headers/linux/cs-protocol.h dummy_src = dummy-backend/dummy_common.c \ dummy-backend/cmtspeech_dummy.c \ cmtspeech_backend_common.c \ cmtspeech_msgs.c cmtspeechdata_common_src = \ sal_debug.c cmtspeechdata_common_inc = \ cmtspeech_backend_common.h \ sal_ring.h \ sal_debug.h cmtspeechdata_pub_inc = \ cmtspeech.h \ cmtspeech_msgs.h cmtspeechdata_pub_inc_nodist = \ cmtspeech_config.h backend_src= backend_cflags= backend_noinst_programs= backend_tests= if USE_BACKEND_DUMMY backend_src += $(dummy_src) backend_cflags += "-I${top_srcdir}/dummy-backend/" endif if USE_BACKEND_NOKIAMODEM backend_src += $(nokiamodem_src) backend_noinst_programs += test_cmtspeech_msgs backend_tests += test_cmtspeech_msgs endif if USE_BACKEND_NULL backend_src += cmtspeech_null.c endif include_HEADERS = $(cmtspeechdata_pub_inc) nodist_include_HEADERS =$(cmtspeechdata_pub_inc_nodist) libcmtspeechdata_la_SOURCES = \ $(cmtspeechdata_common_src) \ $(cmtspeechdata_pub_inc) \ $(backend_src) libcmtspeechdata_la_CFLAGS = \ -prefer-pic $(backend_cflags) libcmtspeechdata_la_LIBADD = -lrt libcmtspeechdata_la_LDFLAGS = \ -Wl,--version-script,$(srcdir)/libcmtspeechdata.ver \ -version-info 1:0:1 # test application sources # ------------------------ TESTS = test_ring \ $(backend_tests) noinst_PROGRAMS = test_ring \ test_cmtspeech \ utils/send_cmtspeech_reset \ utils/cmtspeech_ramp_test \ utils/cmtspeech_ofono_test \ $(backend_noinst_programs) noinst_HEADERS = $(cmtspeechdata_common_inc) \ $(nokiamodem_kernel_inc) test_cmtspeech_msgs_SOURCES = test_cmtspeech_msgs.c test_cmtspeech_msgs_CFLAGS = @CHECK_CFLAGS@ test_cmtspeech_msgs_LDADD = \ @CHECK_LIBS@ \ libcmtspeechdata.la test_cmtspeech_SOURCES = test_cmtspeech.c test_cmtspeech_CFLAGS = @CHECK_CFLAGS@ test_cmtspeech_LDADD = @CHECK_LIBS@ \ libcmtspeechdata.la \ -lrt test_ring_CFLAGS = @CHECK_CFLAGS@ test_ring_LDADD = @CHECK_LIBS@ \ libcmtspeechdata.la utils_send_cmtspeech_reset_SOURCES = utils/send_cmtspeech_reset.c utils_send_cmtspeech_reset_LDADD = \ libcmtspeechdata.la utils_cmtspeech_ramp_test_SOURCES = utils/cmtspeech_ramp_test.c utils_cmtspeech_ramp_test_LDADD = \ libcmtspeechdata.la utils_cmtspeech_ofono_test_SOURCES = utils/cmtspeech_ofono_test.c utils_cmtspeech_ofono_test_CFLAGS = \ @DBUS_CFLAGS@ utils_cmtspeech_ofono_test_LDADD = \ @DBUS_LIBS@ \ libcmtspeechdata.la # pkg-config # ---------- pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libcmtspeechdata.pc $(pkgconfig_DATA): config.status # documentation rules # ------------------- doc: (cd doc && $(MAKE) $(AM_MAKEFLAGS) doc) .PHONY : doc libcmtspeechdata-2.1.1+git20160721~8efc468/README000066400000000000000000000065521112705070200205020ustar00rootroot00000000000000*************************** README for libcmtspeechdata *************************** Copyright (C) 2009,2010 Nokia Corporation. All rights reserved. Introduction ============ This package provides the "libcmtspeechdata" library. Libcmtspeechdata provides an application interface for implementing the speech data path for cellular voice calls. The library depends on other components for setting up and managing the call signaling path. This README file provides information about available environment variables and other similar runtime aspects affecting applications that use libcmtpseechdata. Usage ===== This section provides information for running applications that use libcmtspeechdata. Usage: common environment variables ----------------------------------- CMTSPEECHDEBUG Enable and/or disable built-in traces in components using the cmtspeech tracing interface (sal_debug.h). The value is a comma-separated list of tracing options. Currently supported options are "io" (very low volume, version info, some statistics, warnings and error messages), "trace" (low volume, key state changes and resource management), "debug" (possibly very high volume, enough message to get full understanding what is happening) and "token" (alternative for 'debug', allows to debug low-level execution with a much lower tracing overhead; a single characther per event is printed out to stderr). Prefixing the token with "no" will disable the trace type. E.g. "CMTSPEECHDEBUG=info,trace,nodebug,token". Note that some or all of the debugging options may be disabled at compile time and thus cannot be reactived during runtime. Usage: cmtspeech_dummy backend variables ---------------------------------------- DUMMYSRC Select the source for generated speech frames. Supported options are "sine" (default, generate a sine tone), or a file name (path must start with either "/" or "."). If a file input is used, following restrictions apply: Due to real-time requirements, the whole file must be read to memory before processing starts (e.g. available memory sets the practical limit for file length). The file must be a raw 8/16bit, mono, PCM audio file (with little-endian byte order). Utilities ========= utils/cmtspeech_ofono_test.c ---------------------------- A test app that serves as a minimal example of an app using libcmtspeechdata with oFono integration for call signaling. It listens for oFono call signaling on DBus system bus. When a call is established, it sets up the voice path with libcmtspeechdata, and loops downlink audio as-is to uplink. Remote party will get its uplink looped back. Limitations: as uplink timing is not corrected, so this may not work with all modem modes. utils/cmtspeech_ramp_test.c --------------------------- Test app to verify low-level communication is working towards the modem. Implementation is based on the libcmtspeechdata cmtspeech_test_data_ramp_req() interface. Limitations: very few modems (and firmwares) support this interface. utils/send_cmtspeech_reset.c ---------------------------- Opens modem speech path with libcmtspeechdata and requests reset with cmtspeech_state_change_error(). Further documentation ===================== See the documentation distributed with libcmtspeehcdata-doc package: - /usr/share/doc/libcmtspeechdata-doc/html/ libcmtspeechdata-2.1.1+git20160721~8efc468/README.simple000066400000000000000000000002451112705070200217630ustar00rootroot00000000000000apt-get install pkg-config libpulse-dev cc program.c $(pkg-config --cflags --libs gnomeui) cc -g -o pa_test pa_test.c $(pkg-config --cflags --libs libpulse-simple) libcmtspeechdata-2.1.1+git20160721~8efc468/cmtspeech.h000066400000000000000000000432721112705070200217460ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech.h * * CMT Speech Data protocol library. */ #ifndef INCLUDED_CMTSPEECH_H #define INCLUDED_CMTSPEECH_H #include #include #include #include #include #include /** * General list of TODO items: * * - relay SPC_FLAGS with downlink frames * - rename file to cmtspeechdata.h? */ /* Constants */ /* ------------------------------------------------*/ /** * Protocol states */ enum cmtspeech_state { CMTSPEECH_STATE_INVALID = 0, CMTSPEECH_STATE_DISCONNECTED, CMTSPEECH_STATE_CONNECTED, CMTSPEECH_STATE_ACTIVE_DL, CMTSPEECH_STATE_ACTIVE_DLUL, CMTSPEECH_STATE_TEST_RAMP_PING_ACTIVE }; /** * Enumeration of state transitions */ enum cmtspeech_state_tr { CMTSPEECH_TR_INVALID = -1, CMTSPEECH_TR_0_NO_CHANGE = 0, CMTSPEECH_TR_1_CONNECTED = 1, CMTSPEECH_TR_2_DISCONNECTED = 2, CMTSPEECH_TR_3_DL_START = 3, CMTSPEECH_TR_4_DLUL_STOP = 4, CMTSPEECH_TR_5_PARAM_UPDATE = 5, CMTSPEECH_TR_6_TIMING_UPDATE = 6, CMTSPEECH_TR_7_TIMING_UPDATE = 7, CMTSPEECH_TR_10_RESET = 10, CMTSPEECH_TR_11_UL_STOP = 11, CMTSPEECH_TR_12_UL_START = 12 }; /** * A continuous stream of little-endian 16bit PCM * samples. */ #define CMTSPEECH_BUFFER_TYPE_PCM_S16_LE 0 /* bitmask set by cmtspeech_check_pending() */ #define CMTSPEECH_EVENT_CONTROL (1 << 0) /**< control message available */ #define CMTSPEECH_EVENT_DL_DATA (1 << 1) /**< DL frame available */ #define CMTSPEECH_EVENT_XRUN (1 << 2) /**< DL overrun occured */ /* enum for 'frame_flags' field of cmtspeech_buffer_t */ #define CMTSPEECH_DATA_TYPE_ZERO 0x00 #define CMTSPEECH_DATA_TYPE_INVALID 0x01 #define CMTSPEECH_DATA_TYPE_VALID 0x02 /* bitmask for 'spc_flags' field of cmtspeech_buffer_t */ #define CMTSPEECH_SPC_FLAGS_SPEECH (1 << 0) #define CMTSPEECH_SPC_FLAGS_BFI (1 << 1) #define CMTSPEECH_SPC_FLAGS_ATTENUATE (1 << 2) #define CMTSPEECH_SPC_FLAGS_DEC_RESET (1 << 3) #define CMTSPEECH_SPC_FLAGS_MUTE (1 << 4) #define CMTSPEECH_SPC_FLAGS_PREV (1 << 5) #define CMTSPEECH_SPC_FLAGS_DTX_USED (1 << 6) /* Data structures * ----------------*/ /** * Frame data buffer descriptor. */ struct cmtspeech_buffer_s { int type; /**< buffer type (CMTSPEECH_BUFFER_TYPE_*) */ int count; /**< octets of valid data (including header) */ int pcount; /**< octets of valid payload data */ int size; /**< octets of allocated space */ int frame_flags; /**< frame flags; enum CMTSPEECH_DATATYPE_* */ unsigned int spc_flags; /**< speech codec flags for the frame; for UL: always set to zero, for DL: bitmask of CMTSPEECH_SPC_FLAGS_* */ uint8_t *data; /**< pointer to a buffer of 'size' octets */ uint8_t *payload; /**< pointer to frame payload */ int index; /**< library internal */ int reserved[3]; }; /** * Typedef for cmtspeech_buffer_s */ typedef struct cmtspeech_buffer_s cmtspeech_buffer_t; /** * Protocol state change event */ struct cmtspeech_event_s { int state; /**< new state (CMTSPEECH_STATE_*) */ int prev_state; /**< previous state */ int msg_type; /**< type of the message that caused the state change */ int reserved; /**< reserved */ /** * A copy of the protocol message that caused * the state change (matching 'msg_type' field). */ union { /* msg_type == CMTSPEECH_SSI_CONFIG_RESP: */ struct { uint8_t layout; uint8_t version; /**< deprecated in 1.6.1 */ uint8_t result; } ssi_config_resp; /* msg_type == CMTSPEECH_SPEECH_CONFIG_REQ: */ struct { uint8_t speech_data_stream; uint8_t call_user_connect_ind; uint8_t codec_info; /**< deprecated in 1.5.3 */ uint8_t cellular_info; /**< deprecated in 1.5.3 */ uint8_t sample_rate; uint8_t data_format; bool layout_changed; /**< if true, acquired dl/ul buffers are invalid and need to be released */ } speech_config_req; /* msg_type == CMTSPEECH_TIMING_CONFIG_NTF: */ struct { uint16_t msec; uint16_t usec; struct timespec tstamp; /**< CLOCK_MONOTONIC timestamp when the message was received by HW driver */ } timing_config_ntf; /* msg_type == CMTSPEECH_EVENT_RESET: */ struct { int cmt_sent_req; /**< whether CMT was the initiator */ } reset_done; /* reserved / padding */ struct { int reserved[4]; } reserved; } msg; }; /** * Typedef for cmtspeech_event_s */ typedef struct cmtspeech_event_s cmtspeech_event_t; typedef void cmtspeech_t; /* Interfaces: Core I/O * -------------------- */ /** * Initializes the libcmtspeechdata for use. Should be * called once when application is started. */ void cmtspeech_init(void); /** * Opens the CMT Speech Data connection to the modem. * * @return Instance pointer is returned. On error, * NULL is returned. */ cmtspeech_t* cmtspeech_open(void); /** * Closes CMT Speech Data connection. * * @return Zero on success, a negative error code otherwise. */ int cmtspeech_close(cmtspeech_t *context); /** * Returns a file descriptor that can be used to wait (with * poll()/select()) for events. * * When there is readable data, client should call * cmtspeech_check_events() function. * * @return a file descriptor */ int cmtspeech_descriptor(cmtspeech_t *context); /** * Checks what events are available. * * Should be called when cmtspeech_descriptor() becomes readable. * * @param context self-pointer * @param flags bitmask of pending events (e.g. * CMTSPEECH_EVENT_CONTROL, CMTSPEECH_DL_DATA_AVAIL, ...) * * @return 1 if events available, 0 if not, or a negative error code */ int cmtspeech_check_pending(cmtspeech_t *context, int *flags); /** * Reads a control event and stores it to 'event'. * * This function should be called when cmtspeech_check_pending() * returns flag CMTSPEECH_EVENT_CONTROL. * * @return 0 on success */ int cmtspeech_read_event(cmtspeech_t *context, cmtspeech_event_t *event); /* Interfaces: Event parsing * ------------------------- */ /** * Returns the matching state transition for for 'event'. * * In case either 'context' or 'event' is invalid, * CMTSPEECH_TR_INVALID is returned. * * This function is a helper function and its use is not * mandatory. * * @return enum cmtspeech_state_tr */ int cmtspeech_event_to_state_transition(const cmtspeech_t *context, const cmtspeech_event_t *event); /* Interfaces: Runtime configuration * --------------------------------- */ /** * Sets preference for wideband mode * * If set to enabled, application is assumed to prefer sending and * receiving wideband (i.e. 16kHz sampling rate) speech frames. If * disabled, library assumes only 8kHz sampling rate is supported * and/or preferred. * * This setting will be passed to the modem upon session setup. * The final selection of sampling rate will however be done by * the modem. It is thus possible that modem will send * a CMTSPEECH_SPEECH_CONFIG_REQ event with sampling rate of 16kHz * even though application has disabled wideband support with * this method. * * The sampling rate used to interface with the modem does not * necessarily match the codec sampling rate used on the radio * interface. In other words the modem may resample the voice * frames to match the sampling rate used on modem<->libcmtspeechdata * link. * * By default, wideband mode is disabled after initial cmtspeech_open(). * * This function can only be called when there is no active * session. * * @pre cmtspeech_is_ssi_connection_enabled(context) != true * * @return 0 on success */ int cmtspeech_set_wb_preference(cmtspeech_t *context, bool enabled); /* Interfaces: State management * ---------------------------- */ /** * Returns the current protocol state. * * @return one of CMTSPEECH_STATE_* */ int cmtspeech_protocol_state(cmtspeech_t* context); /** * Is SSI connection enabled? * * The connection is enabled when a succesful SSI_CONFIG_REQ/_RESP * transaction has completed. * * @return boolean answer */ bool cmtspeech_is_ssi_connection_enabled(cmtspeech_t *context); /** * Is speech data stream active? * * The speech frame data stream is active when call parameters * have been delivered and either downlink, or both downlink and * uplink, frames are being sent. * * @return boolean answer */ bool cmtspeech_is_active(cmtspeech_t *context); /** * Signals a change in call signaling server status. * * Note: this reflects the status of call signaling and is not * same as cmtspeech protocol state. * * @param state true call signaling instance has been started * @param state false call signaling instance has terminated */ int cmtspeech_state_change_call_status(cmtspeech_t *context, bool state); /** * Signals a change in call connected status. * * Note: this reflects the status of call signaling and is not * same as cmtspeech protocol state. * * @param state true call has been connected * @param state false call has been disconnected */ int cmtspeech_state_change_call_connect(cmtspeech_t *context, bool state); /** * Signals an error. Protocol state should be reseted. * * @param state true call has been connected * @param state false call has been disconnected * */ int cmtspeech_state_change_error(cmtspeech_t *context); /* Interfaces: Buffer management * -------------------------------------- */ /** * Acquires the next uplink buffer slot. The buffer should be * filled with uplink data to be sent. * * Buffer can be acquired when data stream is active (i.e. * cmtspeech_is_active() is true). Note that it is possible * to acquire buffers already in CMTSPEECH_STATE_ACTIVE_DL * state. * * Following buffer properties are set by the library: 'type', * 'count', 'pcount', 'size', 'data' and 'payload'. Client should * copy payload contents to buffer pointed by 'payload', and * if needed, update the flags in 'frame_flags'. See documentation * of cmtspeech_buffer_t for more information about the struct * fields. * * @pre cmtspeech_is_active() == true * * @return 0 on success, other a negative error code: * -EINVAL: Invalid paramers or state, buffer not acquired. * -ENOBUFS: No free uplink buffers, buffer not acquired. */ int cmtspeech_ul_buffer_acquire(cmtspeech_t *context, cmtspeech_buffer_t **buf); /** * Releases a previously acquired uplink buffer slot back to the * library. The buffer will be sent immediately to the network, so * the caller must release the buffer in sync with network timing. * The timing parameters are delivered as events ('msg_type' * CMTSPEECH_TIMING_CONFIG_NTF). * * Client should update the following buffer properties: contents of * buffer pointed to by 'payload', and 'frame_flags'. * * @return 0 on success, otherwise a negative error code: * -EBUSY: Connection currently busy, frame not sent. Application * should acquire a new buffer and retry sending later. * -EINVAL: Invalid paramers or state, frame not sent. * -EIO: I/O error, frame not sent. * -EPIPE: Protocol state has changed since the buffer was * acquired, frame not sent. */ int cmtspeech_ul_buffer_release(cmtspeech_t *context, cmtspeech_buffer_t *buf); /** * Acquires the next downlink buffer slot. The buffer contains * the next available received frame of data. * * All the buffer properties are set according to the received * downlink frame. * * Note: Application must not write to the buffer memory, * i.e. 'buf->data' and 'buf->payload'. * * @return 0 on success, otherwise a negative error code: * -EINVAL: Invalid paramers or state, buffer not acquired. * -ENODATA: No downlink slot available, buffer not acquired. */ int cmtspeech_dl_buffer_acquire(cmtspeech_t *context, cmtspeech_buffer_t **buf); /** * Releases a previously acquired downlink buffer slot back to the library. * * @return 0 on success, otherwise a negative error code * -ENOENT: The buffer given as argument does not match any * existing acquired buffer. * -EINVAL: Invalid parameters or state. * -EPIPE: An underrun has occured because the buffer was released * too late. */ int cmtspeech_dl_buffer_release(cmtspeech_t *context, cmtspeech_buffer_t *buf); /** * Returns the codec sample rate for the buffer. * * The value reflects the original codec sample rate as it was * received from, or will be sent to, the radio interface. The value * may be different from value of cmtspeech_buffer_sample_rate(), * e.g. in the case where modem does decoding and resamples * the resulting PCM buffers. * * @return * CMTSPEECH_SAMPLE_RATE_NONE: if information not available, * CMTSPEECH_SAMPLE_RATE_8KHZ: 8kHz (narrow band), * CMTSPEECH_SAMPLE_RATE_16KHZ: 16kHz (wide band) * * @see cmtspeech_dl_sample_rate(). */ int cmtspeech_buffer_codec_sample_rate(cmtspeech_buffer_t *context); /** * Returns the sample rate for the buffer. * * @return * CMTSPEECH_SAMPLE_RATE_NONE: if information not available, * CMTSPEECH_SAMPLE_RATE_8KHZ: 8kHz (narrow band), * CMTSPEECH_SAMPLE_RATE_16KHZ: 16kHz (wide band) * * @see cmtspeech_dl_codec_sample_rate(). */ int cmtspeech_buffer_sample_rate(cmtspeech_buffer_t *context); /** * Returns the buffer descriptor pointing to raw downlink * frame at 'data'. * * @see cmtspeech_dl_buffer_release(). */ cmtspeech_buffer_t *cmtspeech_dl_buffer_find_with_data(cmtspeech_t *context, uint8_t *data); /** * Returns the buffer descriptor pointing to raw downlink * frame at 'data'. * * @see cmtspeech_dl_buffer_release(). */ cmtspeech_buffer_t *cmtspeech_dl_buffer_find_with_data(cmtspeech_t *context, uint8_t *data); /* Interfaces: Implementation version information * ---------------------------------------------------- */ /** * Returns the library implementation version as * a NULL-terminated string. */ const char* cmtspeech_version_str(void); /** * Returns the implemented CMT Speech Data protocol version. * * Note that implementation may also provide backwards * compatibility for older versions. */ int cmtspeech_protocol_version(void); /* Interfaces: Access to backend specific functionality * ---------------------------------------------------- */ /** * Returns a string identifying the library backend implementation. * * Backend name can be used to verify which set of custom messages * can be sent (@see cmtspeech_backend_name()). */ const char* cmtspeech_backend_name(cmtspeech_t* context); /** * Passes a custom message to the library backend implementation. * * @param @type a typedef identifying which the message type (backend * specific, @see cmtspeech_backend_name()) * @param args variable number of arguments * * @return 0 on success, otherwise a negative error code */ int cmtspeech_backend_message(cmtspeech_t *self, int type, int args, ...); /* Interfaces: Low level message handling * -------------------------------------- */ /** * Sends the NEW_TIMING_CONFIG_REQ message to CMT. * * @return 0 on success */ int cmtspeech_send_timing_request(cmtspeech_t *context); /** * Sends the SSI_CONFIG_REQ message to CMT. * * @param state enabled or disabled * * @return 0 on success */ int cmtspeech_send_ssi_config_request(cmtspeech_t *context, bool active); /* Interfaces: Test interface * -------------------------- */ /** * Initiates a test sequence where the peer is requested to send * back a test data frame. * * The response frame payload should contain a data ramp, starting * from value 'rampstart', and incremented by one in every octet. * The payload length should be 'ramplen' 32bit words. * * Note: this is a test interface that may not be supported by * all library backends. * * @return 0 on sucess, -1 on error */ int cmtspeech_test_data_ramp_req(cmtspeech_t *context, uint8_t rampstart, uint8_t ramplen); /* Interfaces: Trace messages * -------------------------- */ typedef void (*cmtspeech_trace_handler_t)(int priority, const char *message, va_list args); #define CMTSPEECH_TRACE_ERROR 0 #define CMTSPEECH_TRACE_INFO 3 #define CMTSPEECH_TRACE_STATE_CHANGE 4 #define CMTSPEECH_TRACE_IO 5 #define CMTSPEECH_TRACE_DEBUG 8 #define CMTSPEECH_TRACE_INTERNAL 16 /** * Enables or disables trace message of a given priority level. * * Note, some traces may be disabled at build time, and thus * some traces may be unavailable even if enabled with this * function. * * @param priority one of CMTSPEECH_TRACE_* * @param enabled if true, traces are allowed through */ void cmtspeech_trace_toggle(int priority, bool enabled); /** * Sets the function to call when the library emits a trace * message. * * @param func handler function, or NULL to reset back to default * handler */ int cmtspeech_set_trace_handler(cmtspeech_trace_handler_t func); #endif /* INCLUDED_CMTSPEECH_H */ libcmtspeechdata-2.1.1+git20160721~8efc468/cmtspeech_backend_common.c000066400000000000000000000576131112705070200247640ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmspeech_backend_common.c * * Helper functions for CMT Speech Data library backend * implementations. * * Note: It is NOT mandatory for backends to use this file * at all. E.g. it can separately implement the public * cmtspeech.h interfaces provided by this file, i.e. * cmtspeech_init(), cmtspeech_set_wb_preference(), * cmtspeech_is_active() and so forth. */ #include #include #include #include "cmtspeech.h" #include "cmtspeech_msgs.h" #include "cmtspeech_backend_common.h" #include "sal_debug.h" #define DEBUG_PREFIX "backend_common: " const char* priv_state_to_str(int state) { const char *ret = NULL; ONTRACE(( { static const char *states[] = { "INVALID", "DISCONNECTED", "CONNECTED", "ACTIVE_DL", "ACTIVE_DLUL", "TEST_RAMP_PING_ACTIVE" }; ret = states[state]; } )); return ret; } #if !defined(NDEBUG) #define STATE_ASSERT(v) priv_state_assert(v, state->proto_state, #v, __LINE__) #else #define STATE_ASSERT(v) #endif static int priv_state_assert(int v, int state, const char* str, int line) { if (!v) { TRACE_ERROR(DEBUG_PREFIX "FAILED PROTOCOL ASSERT (line %d, state '%s'):\n\t'%s'", line, priv_state_to_str(state), str); } return v; } static void priv_state_change_to(cmtspeech_bc_state_t *state, int newstate, int priv_state) { if (newstate < 0) { TRACE_STATE_CHANGE(DEBUG_PREFIX "PROTOCOL_STATE <%s> (%d->%d)", priv_state_to_str(state->proto_state), state->priv_state, priv_state); } else { TRACE_STATE_CHANGE(DEBUG_PREFIX "PROTOCOL_STATE <%s> --> <%s> (%d->%d)", priv_state_to_str(state->proto_state), priv_state_to_str(newstate), state->priv_state, priv_state); state->proto_state = newstate; } state->priv_state = priv_state; } static void priv_reset_state_to_disconnected(cmtspeech_bc_state_t *state) { state->call_server_active = false; state->call_connected = false; state->sample_layout = -1; state->proto_state = CMTSPEECH_STATE_INVALID; state->priv_state = -1; state->io_errors = 0; /* state machine init */ priv_state_change_to(state, CMTSPEECH_STATE_DISCONNECTED, BC_STATE_IN_SYNC); } int cmtspeech_bc_open(cmtspeech_bc_state_t *state) { priv_reset_state_to_disconnected(state); /* CMT Speech Data protocol versions: * - v1: 8kHz/NB support only * - v2: like v1, but transfer always 16kHz/WB independently * of the active codec */ state->conf_proto_version = 1; return 0; } /* Public cmtspeech interface functions (common implementation * for all backends): * ----------------------------------------------------------- */ void cmtspeech_init(void) { cmtspeech_initialize_tracing(); } int cmtspeech_set_wb_preference(cmtspeech_t *context, bool enabled) { cmtspeech_bc_state_t *state = cmtspeech_bc_state_object(context); if (cmtspeech_is_ssi_connection_enabled(context) == true) return -1; if (enabled) state->conf_proto_version = 2; else state->conf_proto_version = 1; return 0; } int cmtspeech_event_to_state_transition(const cmtspeech_t *context, const cmtspeech_event_t *cev) { if (cev->prev_state == CMTSPEECH_STATE_DISCONNECTED && cev->state == CMTSPEECH_STATE_CONNECTED) return CMTSPEECH_TR_1_CONNECTED; else if (cev->prev_state == CMTSPEECH_STATE_CONNECTED && cev->state == CMTSPEECH_STATE_DISCONNECTED) return CMTSPEECH_TR_2_DISCONNECTED; else if (cev->prev_state == CMTSPEECH_STATE_CONNECTED && cev->state == CMTSPEECH_STATE_ACTIVE_DL) return CMTSPEECH_TR_3_DL_START; else if ((cev->prev_state == CMTSPEECH_STATE_ACTIVE_DL || cev->prev_state == CMTSPEECH_STATE_ACTIVE_DLUL) && cev->state == CMTSPEECH_STATE_CONNECTED) return CMTSPEECH_TR_4_DLUL_STOP; else if (cev->prev_state == CMTSPEECH_STATE_ACTIVE_DL && cev->state == CMTSPEECH_STATE_ACTIVE_DL) return CMTSPEECH_TR_5_PARAM_UPDATE; else if (cev->msg_type == CMTSPEECH_TIMING_CONFIG_NTF) /* note: we currently cannot distinguish between TR_6 and TR_7, i.e. whether the timing update is a response to our explicit request of new timing, or modem iniated update of timing */ return CMTSPEECH_TR_6_TIMING_UPDATE; else if (cev->msg_type == CMTSPEECH_EVENT_RESET) return CMTSPEECH_TR_10_RESET; else if (cev->prev_state == CMTSPEECH_STATE_ACTIVE_DLUL && cev->state == CMTSPEECH_STATE_ACTIVE_DL) return CMTSPEECH_TR_11_UL_STOP; else if (cev->prev_state == CMTSPEECH_STATE_ACTIVE_DL && cev->state == CMTSPEECH_STATE_ACTIVE_DLUL) return CMTSPEECH_TR_12_UL_START; return CMTSPEECH_TR_INVALID; } int cmtspeech_protocol_state(cmtspeech_t* context) { cmtspeech_bc_state_t *state = cmtspeech_bc_state_object(context); return state->proto_state; } int cmtspeech_bc_state_change_call_status(cmtspeech_t *context, bool server_state) { cmtspeech_bc_state_t *state = cmtspeech_bc_state_object(context); int res = 0; if (server_state != true) { /* case 1.a): State transition to CONNECTED is not complete * as SPEECH_CONFIG_RESP has not been yet sent (due to * locked buffers). This can not happen in normal conditions, * so record an I/O error (possible CMT reset). */ if (state->priv_state == BC_STATE_CONFIG_DEACT_PEND) { SOFT_ASSERT(state->proto_state == CMTSPEECH_STATE_CONNECTED); ++state->io_errors; TRACE_INFO(DEBUG_PREFIX "Call termination blocked due to pending SPEECH_CONFIG_RESP."); } /* case 1.b-i): If protocol state CONNECTED, continue to * deactivate the SSI path immediately. */ else if (state->proto_state == CMTSPEECH_STATE_CONNECTED) { cmtspeech_send_ssi_config_request(context, false); } /* case 1.b-i): CONNECTING, wait until previous transaction * completes. */ else if (state->priv_state == BC_STATE_CONNECTING) { priv_state_change_to(state, -1, BC_STATE_SSI_CONFIG_PEND); } /* notes for other possible states: * case 1.c) DISCONNECTED => nothing to do * case 1.d/e) ACTIVE_DL/DLUL => modem is about to send SPEECH_CONFIG_REQ(0) */ } else { /* note: server_state == true */ /* case: 2.a-i) Protocol state DISCONNECTED (normal case) */ if (state->proto_state == CMTSPEECH_STATE_DISCONNECTED) { cmtspeech_send_ssi_config_request(context, true); } /* case: 2.a-ii) Protocol state DISCONNECTING, we have to * wait until previous SSI_CONFIG transaction * is completed before reconnecting */ else if (state->proto_state == CMTSPEECH_STATE_CONNECTED && state->priv_state == BC_STATE_DISCONNECTING) { priv_state_change_to(state, -1, BC_STATE_SSI_CONFIG_PEND); } /* case: 2.b) Protocol state INVALID or TEST_RAMP_PING_ACTIVE, * continue by performing a reset. */ else if (state->proto_state == CMTSPEECH_STATE_INVALID || state->proto_state == CMTSPEECH_STATE_TEST_RAMP_PING_ACTIVE) { cmtspeech_state_change_error(context); priv_state_change_to(state, -1, BC_STATE_RESET_BEFORE_CONNECT); } /* case: 2.c) Protocol state CONNECTED, do nothing. */ /* case: 2.d) Protocol state ACTIVE* */ else if (state->proto_state == CMTSPEECH_STATE_ACTIVE_DL || state->proto_state == CMTSPEECH_STATE_ACTIVE_DLUL) { /* case: 2.d-i) Spurious active-to-active call status * change during call, ignoring. */ if (state->call_server_active == true) { TRACE_DEBUG("Spurious call status change during active call, ignoring.."); } /* case: 2.d-ii) The CMT has not acked the pending call * termination. Either CMT is alive, but an ack will be * coming shortly, or CMT has crashed. Unfortunately we * don't know for sure which is the case. */ else { if (state->io_errors > 0) { TRACE_ERROR(DEBUG_PREFIX "CMT reset detected, continuing from DISCONNECTED state (prev %s/%d)", priv_state_to_str(state->proto_state), state->priv_state); priv_reset_state_to_disconnected(state); cmtspeech_send_ssi_config_request(context, true); } } } } state->call_server_active = server_state; return res; } int cmtspeech_bc_state_change_call_connect(cmtspeech_t *context, bool connect_state) { cmtspeech_bc_state_t *state = cmtspeech_bc_state_object(context); state->call_connected = connect_state; return 0; } /** * Resets state. This function must be call if it is * detected that the peer endpoint has reset its state. */ void cmtspeech_bc_state_change_reset(cmtspeech_t *context) { cmtspeech_bc_state_t *state = cmtspeech_bc_state_object(context); priv_reset_state_to_disconnected(state); } bool cmtspeech_is_ssi_connection_enabled(cmtspeech_t *context) { cmtspeech_bc_state_t *state = cmtspeech_bc_state_object(context); if (state->proto_state == CMTSPEECH_STATE_CONNECTED || state->proto_state == CMTSPEECH_STATE_ACTIVE_DL || state->proto_state == CMTSPEECH_STATE_ACTIVE_DLUL) return true; return false; } bool cmtspeech_is_active(cmtspeech_t *context) { cmtspeech_bc_state_t *state = cmtspeech_bc_state_object(context); if (state->proto_state == CMTSPEECH_STATE_ACTIVE_DL || state->proto_state == CMTSPEECH_STATE_ACTIVE_DLUL) return true; return false; } /* Backend helper functions * ------------------------ */ /** * Handles a CMT Speech Data control message and creates * a cmtspeech event as result. * * @param inbuf a four-octet control message * @param event a pointer to event structure * * @see cmtspeech_bc_post_command() * * @return 0 on success, -1 on error (unknown message, error parsing, ...) */ int cmtspeech_bc_handle_command(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, cmtspeech_cmd_t inbuf, cmtspeech_event_t *event) { int type, channel; int res = 0; type = cmtspeech_msg_get_type(inbuf); channel = cmtspeech_msg_get_domain(inbuf); SOFT_ASSERT(event != NULL); event->msg_type = type; event->prev_state = state->proto_state; if (type == CMTSPEECH_SPEECH_CONFIG_REQ) { cmtspeech_msg_decode_speech_config_req(inbuf, &event->msg.speech_config_req.speech_data_stream, &event->msg.speech_config_req.call_user_connect_ind, &event->msg.speech_config_req.codec_info, &event->msg.speech_config_req.cellular_info, &event->msg.speech_config_req.sample_rate, &event->msg.speech_config_req.data_format); event->msg.speech_config_req.layout_changed = false; TRACE_DEBUG(DEBUG_PREFIX "Generating event: SPEECH_CONFIG_REQ (conn %d)", event->msg.speech_config_req.call_user_connect_ind); /* state machine assertion */ STATE_ASSERT((state->proto_state == CMTSPEECH_STATE_CONNECTED) || (state->proto_state == CMTSPEECH_STATE_ACTIVE_DL) || (state->proto_state == CMTSPEECH_STATE_ACTIVE_DLUL)); if (event->msg.speech_config_req.speech_data_stream) priv_state_change_to(state, -1, BC_STATE_CONFIG_ACT_PEND); else priv_state_change_to(state, -1, BC_STATE_CONFIG_DEACT_PEND); } else if (type == CMTSPEECH_UPLINK_CONFIG_NTF) { TRACE_DEBUG(DEBUG_PREFIX "Generating event: UPLINK_CONFIG_NTF"); /* state machine assertion */ STATE_ASSERT(state->proto_state == CMTSPEECH_STATE_ACTIVE_DL); if (state->proto_state == CMTSPEECH_STATE_ACTIVE_DL) /* state machine transition (TR12) */ priv_state_change_to(state, CMTSPEECH_STATE_ACTIVE_DLUL, BC_STATE_IN_SYNC); } else if (type == CMTSPEECH_TIMING_CONFIG_NTF) { TRACE_DEBUG(DEBUG_PREFIX "Generating event: TIMING_CONFIG_NTF"); /* XXX: should we have a kernel timestamp? */ cmtspeech_msg_decode_timing_config_ntf(inbuf, &event->msg.timing_config_ntf.msec, &event->msg.timing_config_ntf.usec); /* state machine assertion */ STATE_ASSERT(state->proto_state == CMTSPEECH_STATE_ACTIVE_DL || state->proto_state == CMTSPEECH_STATE_ACTIVE_DLUL); /* XXX: support legacy CMT firmwares */ if (state->proto_state == CMTSPEECH_STATE_ACTIVE_DL) { priv_state_change_to(state, CMTSPEECH_STATE_ACTIVE_DLUL, BC_STATE_IN_SYNC); TRACE_INFO(DEBUG_PREFIX "XXX detected an old CMT firmware that does not send UPLINK_CONFIG_NTF. Support for old versions will be dropped in later versions."); } if (state->priv_state == BC_STATE_TIMING) priv_state_change_to(state, -1, BC_STATE_IN_SYNC); } else if (type == CMTSPEECH_SSI_CONFIG_RESP) { cmtspeech_msg_decode_ssi_config_resp(inbuf, &event->msg.ssi_config_resp.layout, &event->msg.ssi_config_resp.result); event->msg.ssi_config_resp.version = 0; /* deprecated */ TRACE_IO(DEBUG_PREFIX "Generating event: SSI_CONFIG_RESP (layout %u, res %u)", event->msg.ssi_config_resp.layout, event->msg.ssi_config_resp.result); /* state machine assertions */ /* note: it is possible that we go through DISCONNECTED -> * CONNECTING -> DISCONNECTING -> DISCONNECTED without * being CONNECTED at any point */ STATE_ASSERT(state->proto_state == CMTSPEECH_STATE_CONNECTED || state->proto_state == CMTSPEECH_STATE_DISCONNECTED); if (event->msg.ssi_config_resp.result == CMTSPEECH_SSI_CONFIG_RES_SUCCESS) { if (state->priv_state == BC_STATE_CONNECTING) { priv_state_change_to(state, CMTSPEECH_STATE_CONNECTED, BC_STATE_IN_SYNC); state->sample_layout = event->msg.ssi_config_resp.layout; /* step: default to swapped configuration */ if (state->sample_layout == CMTSPEECH_SAMPLE_LAYOUT_NO_PREF) state->sample_layout = CMTSPEECH_SAMPLE_LAYOUT_SWAPPED_LE; } else if (state->priv_state == BC_STATE_DISCONNECTING) { priv_reset_state_to_disconnected(state); TRACE_INFO(DEBUG_PREFIX "CMT Speech Data state machine deactivated."); } else if (state->priv_state == BC_STATE_SSI_CONFIG_PEND) { if (state->call_server_active) { cmtspeech_send_ssi_config_request(pcontext, 1); priv_state_change_to(state, CMTSPEECH_STATE_DISCONNECTED, BC_STATE_CONNECTING); } else { cmtspeech_send_ssi_config_request(pcontext,0); priv_state_change_to(state, CMTSPEECH_STATE_CONNECTED, BC_STATE_DISCONNECTING); } } } else { TRACE_ERROR(DEBUG_PREFIX "ERROR: SSI_CONFIG_RESP returned an error %d", event->msg.ssi_config_resp.result); /* note: do not reset internal state unless it was set * for SSI_CONFIG_REQ */ if (state->priv_state == BC_STATE_CONNECTING || state->priv_state == BC_STATE_DISCONNECTING) { priv_state_change_to(state, -1, BC_STATE_IN_SYNC); } /* note: no other way to recover from this case than to * ask for a protocol reset */ cmtspeech_state_change_error(pcontext); } } else if (type == CMTSPEECH_RESET_CONN_REQ) { TRACE_IO(DEBUG_PREFIX "Generating event: CMTSPEECH_EVENT_RESET (CMT initiated)"); event->msg_type = CMTSPEECH_EVENT_RESET; event->msg.reset_done.cmt_sent_req = 1; /* state machine assertion */ STATE_ASSERT(state->proto_state != CMTSPEECH_STATE_DISCONNECTED); /* state machine transition, to DISCONNECTED (TR10) */ priv_reset_state_to_disconnected(state); } else if (type == CMTSPEECH_RESET_CONN_RESP) { int cached_priv_state = state->priv_state; TRACE_IO(DEBUG_PREFIX "Generating event: CMTSPEECH_EVENT_RESET (APE initiated)"); event->msg_type = CMTSPEECH_EVENT_RESET; event->msg.reset_done.cmt_sent_req = 0; /* state machine assertion */ STATE_ASSERT(state->proto_state != CMTSPEECH_STATE_DISCONNECTED); /* state machine transition, to DISCONNECTED (TR10) */ priv_reset_state_to_disconnected(state); if (cached_priv_state == BC_STATE_RESET_BEFORE_CONNECT) { cmtspeech_send_ssi_config_request(pcontext, 1); } } else if (type == CMTSPEECH_TEST_RAMP_PING) { /* state machine assertion */ STATE_ASSERT(state->proto_state == CMTSPEECH_STATE_DISCONNECTED); /* note: as we send the response immediately on the data path, we * do not need to track the state for inbound * TEST_RAMP_PINGs */ } else { TRACE_ERROR(DEBUG_PREFIX "ERROR: Unknown protocol message %d", type); res = -1; } /* note: see also cmtspeech_bc_complete_event_processing */ return res; } /** * Updates state machine after command 'cmd' has been sent. * * @see cmtspeech_bc_handle_command() * @see cmtspeech_bc_complete_event_processing() */ void cmtspeech_bc_post_command(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, cmtspeech_cmd_t cmd) { int type = cmtspeech_msg_get_type(cmd); int channel = cmtspeech_msg_get_domain(cmd); if (channel == CMTSPEECH_DOMAIN_CONTROL) { if (type == CMTSPEECH_RESET_CONN_REQ) { /* note: RESET_CONN_REQ is only sent on error, so our current * state has no significange any more */ priv_state_change_to(state, CMTSPEECH_STATE_INVALID, BC_STATE_IN_SYNC); } else if (type == CMTSPEECH_SPEECH_CONFIG_RESP) { uint8_t resp; cmtspeech_msg_decode_speech_config_resp(cmd, &resp); /* state machine assertions */ SOFT_ASSERT(state->priv_state == BC_STATE_CONFIG_ACT_PEND || state->priv_state == BC_STATE_CONFIG_DEACT_PEND); /* state machine transitions */ if (resp != 0) { /* note: transaction has failed, do not change the state */ TRACE_ERROR(DEBUG_PREFIX "unable to change %s state due to local error", (state->priv_state == BC_STATE_CONFIG_ACT_PEND) ? "to ACTIVE_DL" : "back to CONNECTED"); priv_state_change_to(state, -1, BC_STATE_IN_SYNC); } else { if (state->proto_state == CMTSPEECH_STATE_CONNECTED) { /* state machine transition (TR3) */ if (state->priv_state == BC_STATE_CONFIG_ACT_PEND) { priv_state_change_to(state, CMTSPEECH_STATE_ACTIVE_DL, BC_STATE_IN_SYNC); cmtspeech_send_timing_request(pcontext); } } else if (state->proto_state == CMTSPEECH_STATE_ACTIVE_DL || state->proto_state == CMTSPEECH_STATE_ACTIVE_DLUL) { if (state->priv_state == BC_STATE_CONFIG_ACT_PEND) { if (state->proto_state == CMTSPEECH_STATE_ACTIVE_DLUL) { /* state machine transition (TR11) */ priv_state_change_to(state, CMTSPEECH_STATE_ACTIVE_DL, BC_STATE_IN_SYNC); } else { /* state machine transition (TR5) */ /* */ ; } } else if (state->priv_state == BC_STATE_CONFIG_DEACT_PEND) { /* state machine transition (TR4) */ priv_state_change_to(state, CMTSPEECH_STATE_CONNECTED, BC_STATE_IN_SYNC); if (state->call_server_active != true) { TRACE_DEBUG(DEBUX_PREFIX "Call Server already inactive, closing SSI connection."); /* note: send request in cmtspeech_bc_post_command() */ cmtspeech_send_ssi_config_request(pcontext, 0); } } } } } } } /** * Completes command processing and fills remaining fields of * the event object. * * @see cmtspeech_bc_handle_command() * @see cmtspeech_bc_post_command() */ void cmtspeech_bc_complete_event_processing(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, cmtspeech_event_t *event) { event->state = state->proto_state; } int cmtspeech_bc_write_command(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, cmtspeech_cmd_t msg, int fd) { int res = write(fd, msg.d.buf, sizeof(msg)); TRACE_IO(DEBUG_PREFIX "wrote %s (%02X:%02X:%02X:%02X), fd %d, res %d.", cmtspeech_msg_type_to_string(msg), msg.d.buf[0], msg.d.buf[1], msg.d.buf[2], msg.d.buf[3], fd, res); if (res == sizeof(msg)) { int channel = cmtspeech_msg_get_domain(msg); if (channel != CMTSPEECH_DOMAIN_INTERNAL) cmtspeech_bc_post_command(state, pcontext, msg); state->io_errors = 0; } else { TRACE_ERROR(DEBUG_PREFIX "ERROR: sending cmd %s failed, res %d", cmtspeech_msg_type_to_string(msg), res); ++state->io_errors; } return res; } int cmtspeech_bc_test_data_ramp_req(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, int fd, uint8_t channel, uint8_t replychannel, uint8_t rampstart, uint8_t ramplen) { int res; cmtspeech_cmd_t msg; /* state machine assertion */ STATE_ASSERT(state->proto_state == CMTSPEECH_STATE_DISCONNECTED); if (state->proto_state != CMTSPEECH_STATE_DISCONNECTED) { TRACE_ERROR(DEBUG_PREFIX "ERROR: call ongoing, cannot send TEST_RAMP_PING!"); return -1; } res = cmtspeech_msg_encode_test_ramp_ping(&msg, channel, replychannel, rampstart, ramplen); if (res == CMTSPEECH_CTRL_LEN) res = cmtspeech_bc_write_command(state, pcontext, msg, fd); if (res != CMTSPEECH_CTRL_LEN) return -1; /* state machine transition (TR12) */ priv_state_change_to(state, CMTSPEECH_STATE_TEST_RAMP_PING_ACTIVE, BC_STATE_IN_SYNC); return 0; } int cmtspeech_bc_test_sequence_received(cmtspeech_bc_state_t *state) { /* state machine assertion */ STATE_ASSERT(state->proto_state == CMTSPEECH_STATE_TEST_RAMP_PING_ACTIVE); /* state machine transition (TRE1) */ priv_state_change_to(state, CMTSPEECH_STATE_DISCONNECTED, BC_STATE_IN_SYNC); return 0; } int cmtspeech_bc_send_timing_request(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, int fd) { int res; cmtspeech_cmd_t msg; res = cmtspeech_msg_encode_new_timing_config_req(&msg); if (res == CMTSPEECH_CTRL_LEN) res = cmtspeech_bc_write_command(state, pcontext, msg, fd); if (res != CMTSPEECH_CTRL_LEN) return -1; priv_state_change_to(state, -1, BC_STATE_TIMING); return 0; } int cmtspeech_bc_send_ssi_config_request(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, int fd, bool state_arg) { cmtspeech_cmd_t msg; uint8_t layout = CMTSPEECH_SAMPLE_LAYOUT_INORDER_LE; int res = cmtspeech_msg_encode_ssi_config_req(&msg, layout, state->conf_proto_version, state_arg == true ? 1 : 0); TRACE_DEBUG(DEBUG_PREFIX "Trying to send SSI_CONFIG_REQ with layout %d, version %d and status %d.", layout, state->conf_proto_version, state_arg == true ? 1 : 0); if (state_arg == false) { /* state machine assertion */ STATE_ASSERT(state->proto_state == CMTSPEECH_STATE_CONNECTED || state->priv_state == BC_STATE_SSI_CONFIG_PEND); if (state->priv_state == BC_STATE_DISCONNECTING) { TRACE_ERROR(DEBUG_PREFIX "ERROR: SSI_CONFIG_REQ(state_arg=0) already pending!"); return -1; } priv_state_change_to(state, -1, BC_STATE_DISCONNECTING); } else { STATE_ASSERT(state->proto_state == CMTSPEECH_STATE_DISCONNECTED || state->priv_state == BC_STATE_SSI_CONFIG_PEND); TRACE_INFO(DEBUG_PREFIX "CMT Speech Data state machine activated with SSI_CONFIG_REQ."); priv_state_change_to(state, -1, BC_STATE_CONNECTING); } if (res == CMTSPEECH_CTRL_LEN) { res = cmtspeech_bc_write_command(state, pcontext, msg, fd); TRACE_IO(DEBUG_PREFIX "Sent SSI_CONFIG_REQ with layout %d, version %d and status %d.", layout, state->conf_proto_version, state_arg == true ? 1 : 0); } if (res != CMTSPEECH_CTRL_LEN) { priv_state_change_to(state, -1, BC_STATE_IN_SYNC); return -1; } return 0; } const char* cmtspeech_version_str(void) { return VERSION; } int cmtspeech_protocol_version(void) { /* note: this is the highest protocol version implemented, * older versions might */ return LIBCMTSPEECHDATA_PROTOCOL_VERSION; } libcmtspeechdata-2.1.1+git20160721~8efc468/cmtspeech_backend_common.h000066400000000000000000000102301112705070200247510ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech_msgs.h * * Helper functions for backend implementations of * CMT Speech Data library. * * Copyright (C) 2008,2009,2010 Nokia Corporation * Contact: Kai Vehmanen * */ #ifndef INCLUDED_CMTSPEECH_BACKEND_COMMON_H #define INCLUDED_CMTSPEECH_BACKEND_COMMON_H #include #include #include #if !defined(LIBCMTSPEECHDATA_PROTOCOL_VERSION) || \ LIBCMTSPEECHDATA_PROTOCOL_VERSION != 2 #error "LIBCMTSPEECHDATA_PROTOCOL_VERSION not defined or does not match implementation." #endif #include "cmtspeech_msgs.h" enum cmtspeech_bc_state { BC_STATE_IN_SYNC = 0, /**< state describes 'proto_state' */ BC_STATE_TIMING, /**< a NEW_TIMING_CONFIG_REQ is currently in progress */ BC_STATE_RESET_BEFORE_CONNECT, BC_STATE_CONNECTING, /**< SSI_CONFIG_REQ(1) has been sent */ BC_STATE_DISCONNECTING, /**< SSI_CONFIG_REQ(0) has been sent */ BC_STATE_SSI_CONFIG_PEND, /**< waiting for previous SSI_CONFIG_REQ */ BC_STATE_CONFIG_ACT_PEND, /**< SPEECH_CONFIG_REQ(1) currently processed, reply not sent */ BC_STATE_CONFIG_DEACT_PEND /**< SPEECH_CONFIG_REQ(0) currently processed, reply not sent */ }; struct cmtspeech_bc_state_s { bool call_server_active; /**< call signaling: whether Call Server is active or not */ bool call_connected; /**< call signaling whether call has been connected */ int proto_state; /**< PROTO_STATE_* */ int priv_state; /**< private state, extension to 'proto_state' */ int sample_layout; int io_errors; /**< counter of fatal i/o errors */ int conf_proto_version; /**< which protocol version to use */ }; typedef struct cmtspeech_bc_state_s cmtspeech_bc_state_t; /* Backend helper functions * ------------------------ */ int cmtspeech_bc_open(cmtspeech_bc_state_t *state); int cmtspeech_bc_handle_command(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, cmtspeech_cmd_t inbuf, cmtspeech_event_t *event); void cmtspeech_bc_post_command(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, cmtspeech_cmd_t resp); void cmtspeech_bc_complete_event_processing(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, cmtspeech_event_t *event); int cmtspeech_bc_write_command(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, cmtspeech_cmd_t msg, int fd); int cmtspeech_bc_send_timing_request(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, int fd); int cmtspeech_bc_send_ssi_config_request(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, int fd, bool state_arg); int cmtspeech_bc_test_data_ramp_req(cmtspeech_bc_state_t *state, cmtspeech_t *pcontext, int fd, uint8_t channel, uint8_t replychannel, uint8_t rampstart, uint8_t ramplen); int cmtspeech_bc_test_sequence_received(cmtspeech_bc_state_t *state); int cmtspeech_bc_state_change_call_connect(cmtspeech_t *context, bool connect_state); int cmtspeech_bc_state_change_call_status(cmtspeech_t *context, bool server_state); void cmtspeech_bc_state_change_reset(cmtspeech_t *context); /* Stub functions that need to be implemented by all backends * ---------------------------------------------------------- */ cmtspeech_bc_state_t *cmtspeech_bc_state_object(cmtspeech_t *context); #endif /* INCLUDED_CMTSPEECH_BACKEND_COMMON_H */ libcmtspeechdata-2.1.1+git20160721~8efc468/cmtspeech_config.h.in000066400000000000000000000026121112705070200236710ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ #ifndef HAVE_CMTSPEECH_CONFIG_H #define HAVE_CMTSPEECH_CONFIG_H #ifndef LIBCMTSPEECHDATA_PROTOCOL_VERSION #define LIBCMTSPEECHDATA_PROTOCOL_VERSION @VERSION_PROTOCOL@ #endif #ifndef LIBCMTSPEECHDATA_MAJOR_VERSION #define LIBCMTSPEECHDATA_MAJOR_VERSION @VERSION_MAJOR@ #endif #ifndef LIBCMTSPEECHDATA_API_VERSION #define LIBCMTSPEECHDATA_API_VERSION @VERSION_LIBRARY_API@ #endif #ifndef LIBCMTSPEECHDATA_MINOR_VERSION #define LIBCMTSPEECHDATA_MINOR_VERSION @VERSION_MINOR@ #endif #endif /* HAVE_CMTSPEECH_CONFIG_H */ libcmtspeechdata-2.1.1+git20160721~8efc468/cmtspeech_msgs.c000066400000000000000000000341151112705070200227660ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010,2011 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech_msgs.c * * Helper functions to encode and parse CMT Speech Data * protocol messages as specified in 'CMT Speech Data * SSI Protocol' document (DCU02180). */ #include "cmtspeech_msgs.h" #if CMTSPEECH_BIG_ENDIAN_CMDS #define BYTE0 0 /* MSB byte */ #define BYTE1 1 #define BYTE2 2 #define BYTE3 3 /* LSB byte */ #elif CMTSPEECH_LITTLE_ENDIAN_CMDS #define BYTE0 3 /* MSB byte */ #define BYTE1 2 #define BYTE2 1 #define BYTE3 0 /* LSB byte */ #else #error "Endianess must be set." #endif /** * Returns the type of control message in 'cmd'. * On success, returned type is one of CMTSPEECH_RESET_CONN, * CSDATA_ACK, CMTSPEECH_CONFIG_RESP, ... On error, -1 is * returned. */ int cmtspeech_msg_get_type(const cmtspeech_cmd_t cmd) { return (int)cmd.d.buf[BYTE0] >> 4; } /** * On success, returns domain number. On error (invalid message), * returns -1. */ int cmtspeech_msg_get_domain(const cmtspeech_cmd_t cmd) { return (int)cmd.d.buf[BYTE0] & 0xf; } const char* cmtspeech_msg_type_to_string(const cmtspeech_cmd_t cmd) { #if !defined(NDEBUG) int domain = cmtspeech_msg_get_domain(cmd); if (domain == CMTSPEECH_DOMAIN_CONTROL) { switch(cmtspeech_msg_get_type(cmd)) { case CMTSPEECH_RESET_CONN_REQ: return "RESET_CONN_REQ"; case CMTSPEECH_RESET_CONN_RESP: return "RESET_CONN_RESP"; case CMTSPEECH_SSI_CONFIG_REQ: return "SSI_CONFIG_REQ"; case CMTSPEECH_SPEECH_CONFIG_REQ: return "SPEECH_CONFIG_REQ"; case CMTSPEECH_TIMING_CONFIG_NTF: return "TIMING_CONFIG_NTF"; case CMTSPEECH_UPLINK_CONFIG_NTF: return "UPLINK_CONFIG_NTF"; case CMTSPEECH_NEW_TIMING_CONFIG_REQ: return "NEW_TIMING_CONFIG_REQ"; case CMTSPEECH_SSI_CONFIG_RESP: return "SSI_CONFIG_RESP"; case CMTSPEECH_SPEECH_CONFIG_RESP: return "SPEECH_CONFIG_RESP"; case CMTSPEECH_TEST_RAMP_PING: return "TEST_RAMP_PING"; default: return ""; } } else if (domain == CMTSPEECH_DOMAIN_INTERNAL) { switch(cmtspeech_msg_get_type(cmd)) { case CMTSPEECH_EVENT_RESET: return "CMTSPEECH_EVENT_RESET"; default: return ""; } } return ""; #else return ""; #endif } /** * Encodes an UL_SPEECH_DATA_FRAME message to buffer pointed * by 'buf'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_ul_data_header(uint8_t *buf, int len, uint16_t frame_counter, uint8_t data_length, uint8_t sample_rate, uint8_t data_type) { if (len < 4) return -1; buf[BYTE0] = frame_counter >> 8; buf[BYTE1] = frame_counter; buf[BYTE2] = 0; /* reserved; */ buf[BYTE3] = (data_length & 0x3) << 4 | (sample_rate & 0x3) << 2 | (data_type & 0x3); return 4; } /** * Decodes CMT speech message in 'buf'. Results are stored to locations * given as arguments. * * @return 0 on success, non-zero otherwise */ int cmtspeech_msg_decode_ul_data_header(uint8_t *buf, int len, uint16_t *frame_counter, uint8_t *data_length, uint8_t *sample_rate, uint8_t *data_type) { if (len < 4) return -1; *frame_counter = buf[BYTE0] << 8 | buf[BYTE1]; *data_length = (buf[BYTE3] >> 4) & 0x3; *sample_rate = (buf[BYTE3] >> 2) & 0x3; *data_type = buf[BYTE3] & 0x3; return 0; } /** * Encodes an DL_SPEECH_DATA_FRAME message to buffer pointed * by 'buf'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_dl_data_header(uint8_t *buf, int len, uint16_t frame_counter, uint8_t spc_flags, uint8_t data_length, uint8_t sample_rate, uint8_t data_type) { return cmtspeech_msg_encode_dl_data_header_v5(buf, len, frame_counter, spc_flags, data_length, sample_rate, CMTSPEECH_SAMPLE_RATE_NONE, data_type); } /** * Encodes an DL_SPEECH_DATA_FRAME message to buffer pointed * by 'buf'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_dl_data_header_v5(uint8_t *buf, int len, uint16_t frame_counter, uint8_t spc_flags, uint8_t data_length, uint8_t sample_rate, uint8_t codec_sample_rate, uint8_t data_type) { if (len < 4) return -1; buf[BYTE0] = frame_counter >> 8; buf[BYTE1] = frame_counter; buf[BYTE2] = (codec_sample_rate & 0x3) << 7 | ((spc_flags >> 2) & 0x1f); buf[BYTE3] = (spc_flags & 0x3) << 6 | (data_length & 0x3) << 4 | (sample_rate & 0x3) << 2 | (data_type & 0x3); return 4; } /** * Decodes CMT speech message in 'buf'. Results are stored to locations * given as arguments. * * @return 0 on success, non-zero otherwise */ int cmtspeech_msg_decode_dl_data_header(uint8_t *buf, int len, uint16_t *frame_counter, uint8_t *spc_flags, uint8_t *data_length, uint8_t *sample_rate, uint8_t *data_type) { uint8_t tmp; return cmtspeech_msg_decode_dl_data_header_v5(buf, len, frame_counter, spc_flags, data_length, sample_rate, &tmp, data_type); } /** * Decodes CMT speech message in 'buf'. Results are stored to locations * given as arguments. * * Variant of cmtspeech_msg_decode_dl_data_header() for ABI * compatibility. * * @return 0 on success, non-zero otherwise */ int cmtspeech_msg_decode_dl_data_header_v5(uint8_t *buf, int len, uint16_t *frame_counter, uint8_t *spc_flags, uint8_t *data_length, uint8_t *sample_rate, uint8_t *codec_sample_rate, uint8_t *data_type) { if (len < 4) return -1; *frame_counter = buf[BYTE0] << 8 | buf[BYTE1]; *spc_flags = ((buf[BYTE2] & 0x1f) << 2) | ((buf[BYTE3] >> 6) & 0x3); *data_length = (buf[BYTE3] >> 4) & 0x3; *sample_rate = (buf[BYTE3] >> 2) & 0x3; *codec_sample_rate = (buf[BYTE2] >> 5) & 0x3; *data_type = buf[BYTE3] & 0x3; return 0; } /** * Encodes a SPEECH_CONFIG_REQ message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_speech_config_req(cmtspeech_cmd_t *cmd, uint8_t speech_data_stream, uint8_t call_user_connecting_ind, uint8_t codec_info, uint8_t cellular_info, uint8_t sample_rate, uint8_t data_format) { cmd->d.buf[BYTE0] = (CMTSPEECH_SPEECH_CONFIG_REQ << 4) | CMTSPEECH_DOMAIN_CONTROL; cmd->d.buf[BYTE1] = 0; /* part of reserved range */ cmd->d.buf[BYTE2] = (speech_data_stream & 0x1) << 3 | (call_user_connecting_ind & 0x1) << 2 | (codec_info & 0xf) >> 2; cmd->d.buf[BYTE3] = ((codec_info & 0xf) << 6) | ((cellular_info & 0x3) << 4) | ((sample_rate & 0x3) << 2) | (data_format & 0x3); return 4; } /** * Decodes CMT speech message in 'cmd'. Results are stored to locations * given as arguments. If an argument is NULL, it is ignored. * * @return 0 on success, non-zero otherwise */ int cmtspeech_msg_decode_speech_config_req(const cmtspeech_cmd_t cmd, uint8_t *speech_data_stream, uint8_t *call_user_connecting_ind, uint8_t *codec_info, uint8_t *cellular_info, uint8_t *sample_rate, uint8_t *data_format) { if (speech_data_stream) *speech_data_stream = (cmd.d.buf[BYTE2] >> 3) & 0x1; if (call_user_connecting_ind) *call_user_connecting_ind = (cmd.d.buf[BYTE2] >> 2) & 0x1; if (codec_info) *codec_info = (cmd.d.buf[BYTE2] << 2 | cmd.d.buf[BYTE3] >> 6) & 0xf; if (cellular_info) *cellular_info = (cmd.d.buf[BYTE3] >> 4) & 0x3; if (sample_rate) *sample_rate = (cmd.d.buf[BYTE3] >> 2) & 0x3; if (data_format) *data_format = cmd.d.buf[BYTE3] & 0x3; return 0; } /** * Encodes a NEW_TIMING_CONFIG_REQ message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ static int priv_cmtspeech_msg_encode_simple_message(cmtspeech_cmd_t *cmd, unsigned simplecmd) { cmd->d.buf[BYTE0] = (simplecmd << 4) | CMTSPEECH_DOMAIN_CONTROL; cmd->d.buf[BYTE1] = 0; cmd->d.buf[BYTE2] = 0; cmd->d.buf[BYTE3] = 0; return 4; } /** * Encodes a NEW_TIMING_CONFIG_REQ message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_new_timing_config_req(cmtspeech_cmd_t *cmd) { return priv_cmtspeech_msg_encode_simple_message(cmd, CMTSPEECH_NEW_TIMING_CONFIG_REQ); } /** * Encodes a UPLINK_CONFIG_NTF message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_uplink_config_ntf(cmtspeech_cmd_t *cmd) { return priv_cmtspeech_msg_encode_simple_message(cmd, CMTSPEECH_UPLINK_CONFIG_NTF); } /** * Encodes a TIMING_CONFIG_NTF message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_timing_config_ntf(cmtspeech_cmd_t *cmd, uint16_t msec, uint16_t usec) { cmd->d.buf[BYTE0] = (CMTSPEECH_TIMING_CONFIG_NTF << 4) | CMTSPEECH_DOMAIN_CONTROL; cmd->d.buf[BYTE1] = (msec & 0x1ff) >> 6; cmd->d.buf[BYTE2] = ((msec & 0x1ff) << 2) | (usec & 0x3ff) >> 8; cmd->d.buf[BYTE3] = usec & 0xff; return 4; } /** * Decodes CMT speech message in 'cmd'. Results are stored to locations * given as arguments. If an argument is NULL, it is ignored. * * @return 0 on success, non-zero otherwise */ int cmtspeech_msg_decode_timing_config_ntf(const cmtspeech_cmd_t cmd, uint16_t *msec, uint16_t *usec) { if (msec) *msec = (cmd.d.buf[BYTE1] & 0x7) << 6 | cmd.d.buf[BYTE2] >> 2; if (usec) *usec = (cmd.d.buf[BYTE2] & 0x3) << 8 | cmd.d.buf[BYTE3]; return 0; } /** * Encodes a SSI_CONFIG_REQ message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_ssi_config_req(cmtspeech_cmd_t *cmd, uint8_t layout, uint8_t version, uint8_t state) { cmd->d.buf[BYTE0] = (CMTSPEECH_SSI_CONFIG_REQ << 4) | CMTSPEECH_DOMAIN_CONTROL; cmd->d.buf[BYTE1] = 0x0; cmd->d.buf[BYTE2] = layout & 0x7; cmd->d.buf[BYTE3] = ((version & 0xf) << 1) | (state & 0x1); return 4; } /** * Decodes CMT speech message in 'cmd'. Results are stored to locations * given as arguments. If an argument is NULL, it is ignored. * * @return 0 on success, non-zero otherwise */ int cmtspeech_msg_decode_ssi_config_req(const cmtspeech_cmd_t cmd, uint8_t *layout, uint8_t *version, uint8_t *state) { if (version) *version = (cmd.d.buf[BYTE3] >> 1) & 0xf; if (state) *state = cmd.d.buf[BYTE3] & 0x1; if (layout) *layout = cmd.d.buf[BYTE2] & 0x7; return 0; } /** * Encodes a SSI_CONFIG_RESP message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_ssi_config_resp(cmtspeech_cmd_t *cmd, uint8_t layout, uint8_t result) { cmd->d.buf[BYTE0] = (CMTSPEECH_SSI_CONFIG_RESP << 4) | CMTSPEECH_DOMAIN_CONTROL; cmd->d.buf[BYTE1] = 0x0; cmd->d.buf[BYTE2] = layout & 0x7; cmd->d.buf[BYTE3] = result & 0x3; return 4; } /** * Decodes CMT speech message in 'cmd'. Results are stored to locations * given as arguments. If an argument is NULL, it is ignored. * * @return 0 on success, non-zero otherwise */ int cmtspeech_msg_decode_ssi_config_resp(const cmtspeech_cmd_t cmd, uint8_t *layout, uint8_t *result) { if (result) *result = cmd.d.buf[BYTE3] & 0x3; if (layout) *layout = cmd.d.buf[BYTE2] & 0x7; return 0; } /** * Decodes CMT speech message in 'cmd'. Results are stored to locations * given as arguments. If an argument is NULL, it is ignored. * * @return 0 on success, non-zero otherwise */ int cmtspeech_msg_decode_speech_config_resp(const cmtspeech_cmd_t cmd, uint8_t *result) { if (result) *result = cmd.d.buf[BYTE3] & 0x1; return 0; } /** * Encodes an RESET_CONN_RESP message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_reset_conn_resp(cmtspeech_cmd_t *cmd) { cmd->d.buf[BYTE0] = (CMTSPEECH_RESET_CONN_RESP << 4) | CMTSPEECH_DOMAIN_CONTROL; cmd->d.buf[BYTE1] = 0x0; cmd->d.buf[BYTE2] = 0x0; cmd->d.buf[BYTE3] = 0x0; return 4; } /** * Encodes an RESET_CONN_RESP message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_reset_conn_req(cmtspeech_cmd_t *cmd) { cmd->d.buf[BYTE0] = (CMTSPEECH_RESET_CONN_REQ << 4) | CMTSPEECH_DOMAIN_CONTROL; cmd->d.buf[BYTE1] = 0x0; cmd->d.buf[BYTE2] = 0x0; cmd->d.buf[BYTE3] = 0x0; return 4; } /** * Encodes a SPEECH_CONFIG_RESP message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_speech_config_resp(cmtspeech_cmd_t *cmd, uint8_t result) { cmd->d.buf[BYTE0] = (CMTSPEECH_SPEECH_CONFIG_RESP << 4) | CMTSPEECH_DOMAIN_CONTROL; cmd->d.buf[BYTE1] = 0x0; cmd->d.buf[BYTE2] = 0x0; cmd->d.buf[BYTE3] = result; return 4; } /** * Decodes CMT speech message in 'cmd'. Results are stored to locations * given as arguments. If an argument is NULL, it is ignored. * * @return 0 on success, non-zero otherwise */ int cmtspeech_msg_decode_test_ramp_ping(const cmtspeech_cmd_t cmd, uint8_t *domain, uint8_t *replydomain, uint8_t *rampstart, uint8_t *ramplen) { if (domain) *domain = cmd.d.buf[BYTE0] & 0xf; if (replydomain) *replydomain = cmd.d.buf[BYTE1] & 0xf; if (rampstart) *rampstart = cmd.d.buf[BYTE2]; if (ramplen) *ramplen = cmd.d.buf[BYTE3]; return 0; } /** * Encodes a TEST_RAMP_PING message to buffer pointed * by 'cmd'. Returns size of encoded data (in octets). */ int cmtspeech_msg_encode_test_ramp_ping(cmtspeech_cmd_t *cmd, uint8_t domain, uint8_t replydomain, uint8_t rampstart, uint8_t ramplen) { cmd->d.buf[BYTE0] = (CMTSPEECH_TEST_RAMP_PING << 4) | domain; cmd->d.buf[BYTE1] = replydomain & 0xf; cmd->d.buf[BYTE2] = rampstart; cmd->d.buf[BYTE3] = ramplen; return 4; } libcmtspeechdata-2.1.1+git20160721~8efc468/cmtspeech_msgs.h000066400000000000000000000162021112705070200227700ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech_msgs.h * * Helper functions to encode and parse CMT Speech * Data protocol messages. */ #ifndef INCLUDED_CMTSPEECH_MSGS_H #define INCLUDED_CMTSPEECH_MSGS_H #include #include /* Build-time configuration */ /* -------------------------*/ /* #define CMTSPEECH_BIG_ENDIAN_CMDS 1 */ #define CMTSPEECH_LITTLE_ENDIAN_CMDS 1 /* CMT Speech Data protocol control message types */ /* ------------------------------------------------*/ #define CMTSPEECH_RESET_CONN_REQ 0x00 #define CMTSPEECH_RESET_CONN_RESP 0x01 #define CMTSPEECH_SSI_CONFIG_REQ 0x02 #define CMTSPEECH_SPEECH_CONFIG_REQ 0x03 #define CMTSPEECH_TIMING_CONFIG_NTF 0x04 #define CMTSPEECH_NEW_TIMING_CONFIG_REQ 0x05 #define CMTSPEECH_SSI_CONFIG_RESP 0x06 #define CMTSPEECH_SPEECH_CONFIG_RESP 0x07 #define CMTSPEECH_UPLINK_CONFIG_NTF 0x08 #define CMTSPEECH_TEST_RAMP_PING 0x0c /* Library event types (must not overlap with control messages) */ /* ------------------------------------------------*/ #define CMTSPEECH_EVENT_STATE_CHANGE 0xff01 #define CMTSPEECH_EVENT_ERROR 0xff02 #define CMTSPEECH_EVENT_RESET 0xff03 /* Header and message sizes */ /* -------------------------*/ #define CMTSPEECH_CTRL_LEN 4 /* command command length, in octets */ #define CMTSPEECH_DATA_HEADER_LEN 4 /* data frame header length, octets */ /* Header fields for control and data frames */ /* ------------------------------------------*/ #define CMTSPEECH_DOMAIN_INTERNAL 0x00 #define CMTSPEECH_DOMAIN_CONTROL 0x01 #define CMTSPEECH_DOMAIN_DATA 0x02 #define CMTSPEECH_SAMPLE_LAYOUT_NO_PREF 0x00 #define CMTSPEECH_SAMPLE_LAYOUT_SWAPPED_LE 0x01 #define CMTSPEECH_SAMPLE_LAYOUT_INORDER_LE 0x02 #define CMTSPEECH_CODEC_INFO_NONE 0 #define CMTSPEECH_CODEC_INFO_GSM_FR 1 #define CMTSPEECH_CODEC_INFO_GSM_EFR 2 #define CMTSPEECH_CODEC_INFO_AMR_NB 3 #define CMTSPEECH_CODEC_INFO_GSM_HR 6 #define CMTSPEECH_CODEC_INFO_AMR_WB 11 #define CMTSPEECH_CELLULAR_INFO_NONE 0x00 #define CMTSPEECH_CELLULAR_INFO_GSM 0x01 #define CMTSPEECH_CELLULAR_INFO_WCDMA 0x02 #define CMTSPEECH_SAMPLE_RATE_NONE 0x00 #define CMTSPEECH_SAMPLE_RATE_8KHZ 0x01 #define CMTSPEECH_SAMPLE_RATE_16KHZ 0x02 #define CMTSPEECH_DATA_FORMAT_NONE 0x00 #define CMTSPEECH_DATA_FORMAT_S16LINPCM 0x01 #define CMTSPEECH_DATA_LENGTH_NONE 0x00 #define CMTSPEECH_DATA_LENGTH_10MS 0x01 #define CMTSPEECH_DATA_LENGTH_20MS 0x02 #define CMTSPEECH_SSI_CONFIG_RES_SUCCESS 0x00 #define CMTSPEECH_SSI_CONFIG_RES_GENERAL_ERROR 0x01 #define CMTSPEECH_SSI_CONFIG_RES_UNSUPPORTED_PROTO 0x02 /* Type definitions */ /* -----------------*/ struct cmtspeech_cmd_s { union { uint8_t buf[CMTSPEECH_CTRL_LEN]; uint32_t cmd; /* in big-endian byte-order */ } d; }; typedef struct cmtspeech_cmd_s cmtspeech_cmd_t; /* Function prototypes / common */ /* -----------------------------*/ int cmtspeech_msg_get_type(const cmtspeech_cmd_t cmd); int cmtspeech_msg_get_domain(const cmtspeech_cmd_t cmd); /* Function prototypes / tracing */ /* ------------------------------*/ const char* cmtspeech_msg_type_to_string(const cmtspeech_cmd_t cmd); /* Function prototypes / data messages */ /* ------------------------------------*/ int cmtspeech_msg_encode_ul_data_header(uint8_t *buf, int len, uint16_t frame_counter, uint8_t data_length, uint8_t sample_rate, uint8_t data_type); int cmtspeech_msg_decode_ul_data_header(uint8_t *buf, int len, uint16_t *frame_counter, uint8_t *data_length, uint8_t *sample_rate, uint8_t *data_type); int cmtspeech_msg_encode_dl_data_header(uint8_t *buf, int len, uint16_t frame_counter, uint8_t spc_flags, uint8_t data_length, uint8_t sample_rate, uint8_t data_type); int cmtspeech_msg_decode_dl_data_header(uint8_t *buf, int len, uint16_t *frame_counter, uint8_t *spc_flags, uint8_t *data_length, uint8_t *sample_rate, uint8_t *data_type); int cmtspeech_msg_decode_dl_data_header_v5(uint8_t *buf, int len, uint16_t *frame_counter, uint8_t *spc_flags, uint8_t *data_length, uint8_t *sample_rate, uint8_t *codec_sample_rate, uint8_t *data_type); int cmtspeech_msg_encode_dl_data_header_v5(uint8_t *buf, int len, uint16_t frame_counter, uint8_t spc_flags, uint8_t data_length, uint8_t sample_rate, uint8_t codec_sample_rate, uint8_t data_type); /* Function prototypes / control messages */ /* ---------------------------------------*/ int cmtspeech_msg_encode_reset_conn_resp(cmtspeech_cmd_t *cmd); int cmtspeech_msg_encode_reset_conn_req(cmtspeech_cmd_t *cmd); int cmtspeech_msg_encode_ssi_config_req(cmtspeech_cmd_t *cmd, uint8_t layout, uint8_t version, uint8_t state); int cmtspeech_msg_decode_ssi_config_req(const cmtspeech_cmd_t cmd, uint8_t *layout, uint8_t *version, uint8_t *state); int cmtspeech_msg_encode_ssi_config_resp(cmtspeech_cmd_t *cmd, uint8_t layout, uint8_t result); int cmtspeech_msg_decode_ssi_config_resp(const cmtspeech_cmd_t cmd, uint8_t *layout, uint8_t *result); int cmtspeech_msg_encode_speech_config_req(cmtspeech_cmd_t *cmd, uint8_t speech_data_stream, uint8_t call_user_connecting_ind, uint8_t codec_info, uint8_t cellular_info, uint8_t sample_rate, uint8_t data_format); int cmtspeech_msg_decode_speech_config_req(const cmtspeech_cmd_t cmd, uint8_t *speech_data_stream, uint8_t *call_user_connecting_ind, uint8_t *codec_info, uint8_t *cellular_info, uint8_t *sample_rate, uint8_t *data_format); int cmtspeech_msg_encode_timing_config_ntf(cmtspeech_cmd_t *cmd, uint16_t msec, uint16_t usec); int cmtspeech_msg_decode_timing_config_ntf(const cmtspeech_cmd_t cmd, uint16_t *msec, uint16_t *usec); int cmtspeech_msg_encode_new_timing_config_req(cmtspeech_cmd_t *cmd); int cmtspeech_msg_decode_speech_config_resp(const cmtspeech_cmd_t cmd, uint8_t *result); int cmtspeech_msg_encode_speech_config_resp(cmtspeech_cmd_t *cmd, uint8_t result); int cmtspeech_msg_encode_uplink_config_ntf(cmtspeech_cmd_t *cmd); int cmtspeech_msg_decode_test_ramp_ping(const cmtspeech_cmd_t cmd, uint8_t *domain, uint8_t *replydomain, uint8_t *rampstart, uint8_t *ramplen); int cmtspeech_msg_encode_test_ramp_ping(cmtspeech_cmd_t *cmd, uint8_t domain, uint8_t replydomain, uint8_t rampstart, uint8_t ramplen); #endif /* INCLUDED_CMTSPEECH_MSGS_H */ libcmtspeechdata-2.1.1+git20160721~8efc468/cmtspeech_nokiamodem.c000066400000000000000000001462451112705070200241500ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech_nokiamodem.c * * A libcmtspeechdata backend implementation for Nokia * hardware (e.g. for Nokia N900). The implementation uses * the /dev/cmt_speech Linux kernel interface to communicate * with the cellular modem. * * This interface is available e.g. in Maemo5 and Maemo6 * kernels. */ /** * General list of TODO items (in priority order): * - none * Longer term: * - low-prio: close the wakeline if no response * is received to RESET */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cmtspeech.h" #include "cmtspeech_msgs.h" #include "cmtspeech_backend_common.h" #include "sal_ring.h" #define CS_COMMAND(x) ((x >> CS_CMD_SHIFT) & 0xf) #define CMD_PARAM_MASK 0xff /* note: the driver kernel interface */ #if HAVE_LINUX_CS_PROTOCOL_H #include #else #include "kernel-headers/linux/cs-protocol.h" #endif /* Build-time configuration */ /* -------------------------------------------------------------------- */ #define EVENT_BUFFER_SIZE 64 #define PCM_SAMPLE_SIZE 2 /* mono/16bit */ #define MAX_SLOT_SIZE (PCM_SAMPLE_SIZE*320+CMTSPEECH_DATA_HEADER_LEN) #define UL_SLOTS 2 #define DL_SLOTS 3 #define SHARED_MEMORY_AREA_PAGE 4096 #define MAX_UL_ERRORS_PAUSE 5 /* pause UL after this many errors */ #define CLOCK_WAKE_UP_DELAY_NS 500000 #if NOKIAMODEM_VDD2LOCK /* maemo5-specific kernel interface for locking memory+ssi bus speed * reference: * - linux/arch/arm/plat-omap/include/mach/omap34xx.h */ #define PM_VDD2_LOCK_TO_OPP3 3 #define PM_VDD2_UNLOCK 0 #define PM_VDD2_LOCK_INTERFACE "/sys/power/vdd2_lock" #endif /* support use of 'swapped little endian' sample layout * for transfering speech data frames */ #define PROTOCOL_SUPPORT_SAMPLE_SWAP 1 #include "sal_debug.h" #define DEBUG_PREFIX "nokiamodem_backend: " /* Data types */ /* -------------------------------------------------------------------- */ enum { STATE_IDLE, /**< call server not active */ STATE_INITIALIZED, /**< call has been activated on CMT side */ STATE_MEDIA_FLOWING, /**< at least DL frame are being sent */ }; enum { BUF_LOCKED = 1, BUF_INVALID = 1 << 1, BUF_XRUN = 1 << 2, BUF_LAST = 1 << 3, }; enum { WAKELINE_CALL = 1 << 0, WAKELINE_RESET = 1 << 1, WAKELINE_TEST_RAMP_PING = 1 << 2, }; enum DriverFeatures { DRIVER_FEAT_ROLLING_RX_PTR = 1 << 0, }; struct nokiamodem_buffer_desc_s { cmtspeech_buffer_t bd; int flags; }; typedef struct nokiamodem_buffer_desc_s nokiamodem_buffer_desc_t; struct nokiamodem_driver_state_s { int fd; /**< driver-io: cmt_speech driver handle */ int wakeline_users; /**< driver-io: bitmask of wakeline users */ int flags; /**< driver-io: bitmask of DriverFeatures enum */ uint8_t *buf; /**< driver-io: mmap()'ed driver buffer */ size_t buflen; /**< driver-io: size of 'buf' */ uint8_t *dlswapbuf; /**< driver-io: temporary buffer for public DL buffers */ ring_buffer_t evbuf; /**< driver-io: queued received events */ uint32_t rx_offsets[DL_SLOTS]; uint32_t tx_offsets[UL_SLOTS]; uint32_t tstamp_rx_ctrl_offset; }; typedef struct nokiamodem_driver_state_s nokiamodem_driver_state_t; struct cmtspeech_nokiamodem_s { nokiamodem_driver_state_t d; /**< driver/ext-resource state */ cmtspeech_bc_state_t bcstate; /**< backend-common protocol state */ bool speech_config_resp_pend; /**< buf state: response waiting for to be sent */ unsigned int slot_size; /**< buf state: data frame slot (header+payload) size in octets */ uint8_t conf_sample_rate; /**< buf state: CMTSPEECH_SAMPLE_RATE_* */ uint8_t conf_data_length; /**< buf state: CMTSPEECH_DATA_LENGTH_* */ int ul_errors; /**< buf state: number of consecutive UL errors */ int rx_ptr_hw; /**< buf state: next ptr hw driver will write to, -1 if buffer not yet configured */ int rx_ptr_appl; /**< buf state: next ptr to give out to the app, -1 if no driver buffer is yet available */ int ul_slot_app; /**< buf state: next slot to give to the app, -1 if buffer not yet configured */ nokiamodem_buffer_desc_t dlbufdesc[DL_SLOTS]; /**< buf state: DL buffer descs */ nokiamodem_buffer_desc_t ulbufdesc[UL_SLOTS]; /**< buf state: DL buffer descs */ }; typedef struct cmtspeech_nokiamodem_s cmtspeech_nokiamodem_t; #define CMTSPEECH_BACKEND_ID "cmtspeech_nokiamodem" /* Definitions derived from build-time configuration */ /* -------------------------------------------------------------------- */ #if CMTSPEECH_BIG_ENDIAN_CMDS #define BYTE0 0 /* MSB byte */ #define BYTE1 1 #define BYTE2 2 #define BYTE3 3 /* LSB byte */ #elif CMTSPEECH_LITTLE_ENDIAN_CMDS #define BYTE0 3 /* MSB byte */ #define BYTE1 2 #define BYTE2 1 #define BYTE3 0 /* LSB byte */ #else #error "Endianess must be set." #endif static int priv_setup_driver_bufconfig(cmtspeech_nokiamodem_t *priv); static void priv_reset_buf_state_to_disconnected(cmtspeech_nokiamodem_t *priv); static void priv_initialize_after_peer_reset(cmtspeech_nokiamodem_t *priv); /* Function definitions */ /* -------------------------------------------------------------------- */ /** * Encodes a driver internal message 'type' to buffer pointed * by 'cmd', and param of 'param'. Returns size of encoded data (in octets). * * @param type is one of UL_DATA_READY, ... */ static int priv_msg_encode_driver_message(cmtspeech_cmd_t *cmd, uint8_t type, uint8_t param) { cmd->d.buf[BYTE0] = (type << 4) | CMTSPEECH_DOMAIN_INTERNAL; cmd->d.buf[BYTE1] = 0x0; cmd->d.buf[BYTE2] = 0x0; cmd->d.buf[BYTE3] = param & CMD_PARAM_MASK; return 4; } static int priv_write_data(cmtspeech_nokiamodem_t *priv, cmtspeech_cmd_t msg) { int res = write(priv->d.fd, msg.d.buf, sizeof(msg)); TRACE_DEBUG(DEBUG_PREFIX "wrote %s, fd %d, res %d.", cmtspeech_msg_type_to_string(msg), priv->d.fd, res); /* note: priv->bcstate.io_errors are not updated for data * i/o for performance reasons */ return res; } static int priv_write(cmtspeech_nokiamodem_t *priv, cmtspeech_cmd_t msg) { return cmtspeech_bc_write_command(&priv->bcstate, priv, msg, priv->d.fd); } #if NOKIAMODEM_VDD2LOCK /** * Lock/unlocks system resources so that no changes in DVFS mods * that would impact SSI driver clocking will be initiated. */ static void priv_set_ssi_lock(cmtspeech_nokiamodem_t *priv, bool enabled) { int fd; fd = open(PM_VDD2_LOCK_INTERFACE, O_WRONLY, 0); if (fd >= 0) { char buf[2]; int res; snprintf(buf, sizeof(buf), "%hu", enabled == true ? PM_VDD2_LOCK_TO_OPP3 : PM_VDD2_UNLOCK); res = write(fd, buf, sizeof(buf)); TRACE_IO("setting VDD2 lock to '%s', res %d.", buf, res); close(fd); } else { TRACE_IO(DEBUG_PREFIX "Unable to lock VDD2, dev %s ('%s').", PM_VDD2_LOCK_INTERFACE, strerror(errno)); } } #endif /** * Allocates SSI wakeline from the driver. * * Note: this function requires a kernel driver that uses * the SSI control channel for wakeline signaling. * * @param priv context * @param id bitmask identifying the wakeline user (see WAKELINE_*) * @return zero on success, non-zero if errors in raising * the wakeline */ static int priv_acquire_wakeline(cmtspeech_nokiamodem_t *priv, int id) { int res = 0; if (priv->d.wakeline_users == 0) { unsigned int status = 1; res = ioctl (priv->d.fd, CS_SET_WAKELINE, &status); TRACE_IO(DEBUG_PREFIX "Toggled SSI wakeline to %u by id %02x (res %d).", status, id, res); #if NOKIAMODEM_VDD2LOCK /* step: lock VDD2 whenever modem needs to be able to send * messages towards us */ priv_set_ssi_lock(priv, true); #endif /* step: this is ugly, but as the hw interface does not provide means to get * an indication when modem is ready, a small delay is * needed after raising the wakeline */ struct timespec tv; tv.tv_sec = 0; tv.tv_nsec = CLOCK_WAKE_UP_DELAY_NS; nanosleep(&tv, NULL); } priv->d.wakeline_users |= id; return res; } /** * Releases SSI driver wakeline. * * @param priv context * @param id bitmask identifying the wakeline user (see WAKELINE_*) * @return zero on success, non-zero if errors in raising * the wakeline */ static int priv_release_wakeline(cmtspeech_nokiamodem_t *priv, int id) { int res = 0; SOFT_ASSERT(priv->d.wakeline_users != 0); if (priv->d.wakeline_users != 0) { priv->d.wakeline_users &= ~id; if (priv->d.wakeline_users == 0) { unsigned int status = 0; res = ioctl (priv->d.fd, CS_SET_WAKELINE, &status); TRACE_IO(DEBUG_PREFIX "Toggled SSI wakeline to %u by id %02x (res %d).", status, id, res); #if NOKIAMODEM_VDD2LOCK /* step: unlock VDD2 whenever we are sure modem no longer needs * needs to send messages towards us */ priv_set_ssi_lock(priv, false); #endif } } return res; } static void priv_reset_wakeline_state(cmtspeech_nokiamodem_t *priv) { unsigned int status = 0; int res; TRACE_IO(DEBUG_PREFIX "Reseting SSI wakeline state (user mask %x at reset).", priv->d.wakeline_users); #if NOKIAMODEM_VDD2LOCK /* step: make sure VDD2 is unlocked */ if (priv->d.wakeline_users != 0) { priv_set_ssi_lock(priv, false); } #endif res = ioctl (priv->d.fd, CS_SET_WAKELINE, &status); SOFT_ASSERT(res == 0); priv->d.wakeline_users = 0; } /** * Sends a RESET_CONN_REQ message to the modem. * * As modem is currently not able to toggle the SSI wakeline * by itself, we need to keep the wakeline up until we get * a response. Otherwise the modem would not be able to respond. * * See also priv_handle_reset_response() and priv_handle_reset_conn_req(). */ static int priv_send_reset(cmtspeech_nokiamodem_t *priv) { int res = 0; res = priv_acquire_wakeline(priv, WAKELINE_RESET); if (res == 0) { cmtspeech_cmd_t msg; cmtspeech_msg_encode_reset_conn_req(&msg); /* note: priv_write() causes a state transition by * call cmtspeech_bc_post_command() */ res = priv_write(priv, msg); if (res < 0) { res = priv_release_wakeline(priv, WAKELINE_RESET); } } /* step: Reset the driver buffer configuration to initial * state. This is done already after sending the * request as it is possible that CMT has become * unavailable and there will be no response. * * Note that we must still keep the wakeline up. * Otherwise CMT would not be able to send a response. * See priv_handle_reset_response(). */ priv->slot_size = 0; priv_setup_driver_bufconfig(priv); return res; } /** * Handles a received RESET_CONN_RESP. * * See also priv_send_reset() and priv_handle_reset_conn_req(). */ static void priv_handle_reset_response(cmtspeech_nokiamodem_t *priv) { priv_release_wakeline(priv, WAKELINE_RESET); return; } static void priv_initialize_buffer_descriptor(nokiamodem_buffer_desc_t *bd, uint8_t *slotbuf, unsigned int slot_size, int frame_flags, int index, int desc_flags) { bd->bd.type = CMTSPEECH_BUFFER_TYPE_PCM_S16_LE; bd->bd.count = slot_size; bd->bd.pcount = slot_size - CMTSPEECH_DATA_HEADER_LEN; bd->bd.size = slot_size; bd->bd.frame_flags = frame_flags; bd->bd.data = slotbuf; bd->bd.payload = slotbuf + CMTSPEECH_DATA_HEADER_LEN; bd->bd.index = index; bd->flags = desc_flags; } static void priv_initialize_tx_buffer_descriptors_mmap(cmtspeech_nokiamodem_t *priv, int desc_flags) { int i; struct cs_mmap_config_block *mmap_cfg = (struct cs_mmap_config_block *)priv->d.buf; for(i = 0; i < UL_SLOTS; i++) { uint8_t *slotbuf_i = priv->d.buf + mmap_cfg->tx_offsets[i]; priv_initialize_buffer_descriptor(&priv->ulbufdesc[i], slotbuf_i, priv->slot_size, 0, i, desc_flags); } } static void priv_initialize_rx_buffer_descriptors_mmap(cmtspeech_nokiamodem_t *priv, int desc_flags) { int i; struct cs_mmap_config_block *mmap_cfg = (struct cs_mmap_config_block *)priv->d.buf; for(i = 0; i < DL_SLOTS; i++) { uint8_t *slotbuf_i = priv->d.buf + mmap_cfg->rx_offsets[i]; priv_initialize_buffer_descriptor(&priv->dlbufdesc[i], slotbuf_i, priv->slot_size, 0, i, desc_flags); } } /** * Reinitializes the DL buffer descriptors in case the sample * layout has changed. * * Note: priv_initialize_dl_buffer_descriptors*() must be called * at least once before this function. */ static void priv_update_dl_buffer_descriptors(cmtspeech_nokiamodem_t *priv) { int i; for(i = 0; i < DL_SLOTS; i++) { uint8_t *slotbuf_i; if (priv->bcstate.sample_layout == CMTSPEECH_SAMPLE_LAYOUT_SWAPPED_LE) { slotbuf_i = priv->d.dlswapbuf + i * priv->slot_size; } else { slotbuf_i = priv->d.buf + priv->d.rx_offsets[i]; } priv_initialize_buffer_descriptor(&priv->dlbufdesc[i], slotbuf_i, priv->slot_size, priv->dlbufdesc[i].bd.frame_flags, i, 0); } } static void priv_handle_ssi_config_resp(cmtspeech_nokiamodem_t *priv) { /* step: release SSI wakeline */ if (priv->bcstate.proto_state == CMTSPEECH_STATE_DISCONNECTED && priv->bcstate.priv_state != BC_STATE_CONNECTING) { /* note: only disable the wakeline when call is terminated, * not after each transaction */ priv_release_wakeline(priv, WAKELINE_CALL); } else { /* note: In case sample buffers are already set up, reinitialize * the DL buffers in case modem has requested a different * sample layout. For UL, reinitialization is not * needed as sample-swapping is done in place. */ if (priv->slot_size > 0) priv_update_dl_buffer_descriptors(priv); } return; } static inline int priv_locked_bufdescs(cmtspeech_nokiamodem_t *priv, bool verbose) { int i, locked = 0; for(i = 0; i < UL_SLOTS; i++) if (priv->ulbufdesc[i].flags & BUF_LOCKED) { ++locked; if (verbose == true) TRACE_IO(DEBUG_PREFIX "UL buf %i(%p,data:%p) locked.", i, &priv->ulbufdesc[i].bd, priv->ulbufdesc[i].bd.data); } for(i = 0; i < DL_SLOTS; i++) if (priv->dlbufdesc[i].flags & BUF_LOCKED) { ++locked; if (verbose == true) TRACE_IO(DEBUG_PREFIX "DL buf %i(%p,data:%p) locked.", i, &priv->dlbufdesc[i].bd, priv->dlbufdesc[i].bd.data); } return locked; } /** * Marks all buffer descriptors as invalid. This is needed * when buffer layout needs to be changed, but application * is holding on to some buffer descriptors. The actual * change in layout has to be postponed until all invalid * buffers are released back to the library. * * @see priv_drvbuf_layout_change_buffer_released() */ static int priv_invalidate_buffer_slots(cmtspeech_nokiamodem_t *priv) { int i; for(i = 0; i < UL_SLOTS; i++) priv->ulbufdesc[i].flags |= BUF_INVALID; for(i = 0; i < DL_SLOTS; i++) priv->dlbufdesc[i].flags |= BUF_INVALID; return 0; } /** * Resets state related to data path configuration. Should be * only called from priv_setup_driver_bufconfig(). */ static void priv_reset_buf_state_to_disconnected(cmtspeech_nokiamodem_t *priv) { priv->slot_size = 0; priv->conf_sample_rate = (uint8_t)-1; priv->conf_data_length = (uint8_t)-1; priv->speech_config_resp_pend = false; priv->ul_errors = 0; priv->rx_ptr_hw = -1; priv->rx_ptr_appl = -1; priv->ul_slot_app = -1; memset(priv->dlbufdesc, 0, DL_SLOTS * sizeof(nokiamodem_buffer_desc_t)); memset(priv->ulbufdesc, 0, UL_SLOTS * sizeof(nokiamodem_buffer_desc_t)); priv_invalidate_buffer_slots(priv); SOFT_ASSERT(priv_locked_bufdescs(priv, true) == 0); } cmtspeech_t* cmtspeech_open(void) { cmtspeech_nokiamodem_t *priv = malloc(sizeof(cmtspeech_nokiamodem_t)); int fd = open(CS_DEV_FILE_NAME, O_RDWR); size_t ringbufsize = EVENT_BUFFER_SIZE * sizeof(cmtspeech_event_t); uint8_t *ringbufdata = malloc(ringbufsize); uint8_t *mmap_buf = NULL; TRACE_INFO(DEBUG_PREFIX "Opening device, libcmtspeechdata v%s.", VERSION); if (fd >= 0) mmap_buf = (uint8_t*)mmap(NULL, SHARED_MEMORY_AREA_PAGE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (priv && fd >= 0 && ringbufdata && mmap_buf != MAP_FAILED) { TRACE_IO(DEBUG_PREFIX "Succesfully opened device %s (fd %d).", CS_DEV_FILE_NAME, fd); cmtspeech_bc_open(&priv->bcstate); priv->d.wakeline_users = 0; priv->d.fd = fd; priv->d.flags = 0; ring_buffer_init(&priv->d.evbuf, ringbufdata, ringbufsize); /* note: we define the memory layout */ priv->d.buf = mmap_buf; priv->d.buflen = SHARED_MEMORY_AREA_PAGE; TRACE_IO(DEBUG_PREFIX "Mapped memory area of %u octets at %p.", priv->d.buflen, priv->d.buf); #if PROTOCOL_SUPPORT_SAMPLE_SWAP priv->d.dlswapbuf = malloc(MAX_SLOT_SIZE * DL_SLOTS); #else priv->d.dlswapbuf = NULL; #endif priv_reset_buf_state_to_disconnected(priv); } else { TRACE_ERROR(DEBUG_PREFIX "unable to open device %s ('%s').", CS_DEV_FILE_NAME, strerror(errno)); if (mmap_buf) munmap(mmap_buf, SHARED_MEMORY_AREA_PAGE); if (fd >= 0) close(fd); if (priv) free(priv); if (ringbufdata) free(ringbufdata); priv = 0; } return (cmtspeech_t*)priv; } int cmtspeech_close(cmtspeech_t *context) { int res = 0; if (context) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; priv_reset_wakeline_state(priv); if (priv->d.buf) munmap(priv->d.buf, priv->d.buflen); close(priv->d.fd); if (priv->d.evbuf.data) free(priv->d.evbuf.data); if (priv->d.dlswapbuf) free(priv->d.dlswapbuf); /* step: finally free the context pointer itself*/ free(priv); } else res = -1; return res; } int cmtspeech_descriptor(cmtspeech_t *context) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; return priv->d.fd; } /** * Queues a control event to internal buffer. * * If the queue gets full, the new event will overwrite * the older event currently in the queue. * * @return 0 on success, -1 if queue was full and existing * old data was overwritten */ static int priv_queue_control_event(cmtspeech_nokiamodem_t *priv, const cmtspeech_event_t *event) { int cavail = ring_buffer_cavail_for_write(&priv->d.evbuf); uint8_t *to = priv->d.evbuf.data + priv->d.evbuf.write_idx; int res = 0; int eventsize = sizeof(*event); if (cavail < eventsize) { uint8_t *from = priv->d.evbuf.data + priv->d.evbuf.read_idx; const cmtspeech_event_t *oldev = (const cmtspeech_event_t *)from; int avail = ring_buffer_avail_for_write(&priv->d.evbuf); TRACE_ERROR(DEBUG_PREFIX "control event queue overflow " "(lostmsg:%d, newmsg:%d, avail=%u, cavail=%u, event=%u)", oldev->msg_type, event->msg_type, avail, cavail, eventsize); ring_buffer_move_read(&priv->d.evbuf, eventsize); cavail = ring_buffer_cavail_for_write(&priv->d.evbuf); res = -1; } SOFT_ASSERT(cavail >= eventsize); memcpy(to, event, eventsize); ring_buffer_move_write(&priv->d.evbuf, eventsize); return res; } /** * Dequeues a control event * * @return 0 on success, -1 if queue is empty and no event * can be read */ static int priv_dequeue_control_event(cmtspeech_nokiamodem_t *priv, cmtspeech_event_t *event) { uint8_t *from = priv->d.evbuf.data + priv->d.evbuf.read_idx; int cavail = ring_buffer_cavail_for_read(&priv->d.evbuf); int eventsize = sizeof(*event); if (cavail < eventsize) { int avail = ring_buffer_avail_for_read(&priv->d.evbuf); TRACE_IO(DEBUG_PREFIX "notice: control event dequeue with no data " "(avail=%u, cavail=%u, event=%u)", avail, cavail, eventsize); return -1; } memcpy(event, from, eventsize); ring_buffer_move_read(&priv->d.evbuf, eventsize); return 0; } static int priv_setup_driver_bufconfig_v2api(cmtspeech_nokiamodem_t *priv) { struct cs_buffer_config drvcfg; int res, desc_flags = 0; unsigned int if_ver; memset(&drvcfg, 0, sizeof(drvcfg)); /* step: fill the driver config struct */ drvcfg.buf_size = priv->slot_size; drvcfg.rx_bufs = DL_SLOTS; drvcfg.tx_bufs = UL_SLOTS; drvcfg.flags = CS_FEAT_TSTAMP_RX_CTRL | CS_FEAT_ROLLING_RX_COUNTER; res = ioctl(priv->d.fd, CS_GET_IF_VERSION, &if_ver); if (res < 0) { if_ver = 0; } res = ioctl(priv->d.fd, CS_CONFIG_BUFS, &drvcfg); TRACE_IO(DEBUG_PREFIX "Initialized driver buffer: res %d, params size=%u.", res, drvcfg.buf_size); if (res == 0) { struct cs_mmap_config_block *mmap_cfg = (struct cs_mmap_config_block *)priv->d.buf; int i; TRACE_IO(DEBUG_PREFIX "mmap_cfg: ver=%u, buf_size=%u, rxbufs=%u, txbufs=%u", if_ver, mmap_cfg->buf_size, mmap_cfg->rx_bufs, mmap_cfg->tx_bufs); /* note: rolling rx pointer feature introduced in v1 */ if (if_ver > 0) priv->d.flags |= DRIVER_FEAT_ROLLING_RX_PTR; /* note: run following only when activating */ if (priv->slot_size > 0) { for(i = 0; i < DL_SLOTS; i++) TRACE_IO(DEBUG_PREFIX "mmap_cfg: rxbuf #%u = %u", i, mmap_cfg->rx_offsets[i]); for(i = 0; i < UL_SLOTS; i++) TRACE_IO(DEBUG_PREFIX "mmap_cfg: txbuf #%u = %u", i, mmap_cfg->tx_offsets[i]); priv_initialize_rx_buffer_descriptors_mmap(priv, desc_flags); priv_initialize_tx_buffer_descriptors_mmap(priv, desc_flags); priv->d.tstamp_rx_ctrl_offset = offsetof(struct cs_mmap_config_block, tstamp_rx_ctrl); TRACE_IO(DEBUG_PREFIX "mmap_cfg: rx-ctrl-tstamp=%u", priv->d.tstamp_rx_ctrl_offset); } } else { TRACE_ERROR(DEBUG_PREFIX "CS_CONFIG_BUFS returned an error (%d): %s", errno, strerror(errno), drvcfg.buf_size); } return res; } /** * Configures the driver for data frame exchange. */ static int priv_setup_driver_bufconfig(cmtspeech_nokiamodem_t *priv) { int res; if (priv->slot_size == 0) { /* note: speech data transfer terminated, reset buffer state */ priv_reset_buf_state_to_disconnected(priv); } else { /* note: driver speech frame layout changed */ priv->ul_errors = 0; priv->rx_ptr_hw = -1; priv->rx_ptr_appl = -1; priv->ul_slot_app = 0; } /* step: pass new parameters to the driver */ res = priv_setup_driver_bufconfig_v2api(priv); if (res < 0) { TRACE_ERROR(DEBUG_PREFIX "Unable to set up buffer config for call"); } return res; } /** * Sets up a new buffer configuration to driver and * sends a reply to the CMT (SPEECH_CONFIG_RESP). * * @param priv context pointer * * @return 0 on success, non-zero error otherwise */ static int priv_setup_and_send_speech_config_reply(cmtspeech_nokiamodem_t *priv) { int res, setupres; uint8_t reply_result = 0; cmtspeech_cmd_t respcmd; priv->speech_config_resp_pend = false; setupres = priv_setup_driver_bufconfig(priv); /* step: convert result into protocol syntax */ reply_result = (setupres == 0 ? 0 : 1); /* step: encode and send the reply to CMT */ res = cmtspeech_msg_encode_speech_config_resp(&respcmd, reply_result); /* step: send the response */ res = priv_write(priv, respcmd); if (res == CMTSPEECH_CTRL_LEN) { res = 0; } else res = -1; if (setupres != 0) { /* we cannot properly receover from local speech_config error, * so send a request to reset the state to modem */ TRACE_ERROR(DEBUG_PREFIX "Setting up driver buffers failed %d.", res); priv_invalidate_buffer_slots(priv); priv_send_reset(priv); } return res; } /** * Completes processing of SPEECH_CONFIG_REQ. * * This function should be called when SPEECH_CONFIG_REQ * processing is blocked due to locked buffers, and when * one or more buffers have been released by * the application. When the last locked buffer has * been released, this function will complete * transaction and send a SPEECH_CONFIG_RESP. This * process also involves resetting the driver buffer * layout and restarting the DMA requests. */ static int priv_drvbuf_layout_change_buffer_released(cmtspeech_nokiamodem_t *priv, nokiamodem_buffer_desc_t*descs, cmtspeech_buffer_t *buf) { nokiamodem_buffer_desc_t *desc = &descs[buf->index]; SOFT_ASSERT(priv->speech_config_resp_pend == true); SOFT_ASSERT(desc->flags & BUF_LOCKED); SOFT_ASSERT(desc->flags & BUF_INVALID); desc->flags &= ~BUF_LOCKED; int locked = priv_locked_bufdescs(priv, true); TRACE_IO(DEBUG_PREFIX "Buffer release during layout change, locked %d.", locked); if (locked == 0) { int res = priv_setup_and_send_speech_config_reply(priv); if (res != 0) { TRACE_ERROR(DEBUG_PREFIX "Sending SPEECH_CONFIG_RESP (delayed) failed with %d.", res); priv_invalidate_buffer_slots(priv); } SOFT_ASSERT(priv->speech_config_resp_pend != true); } return 0; } /** * Handles an incoming SPEECH_CONFIG_REQ message. */ static int priv_handle_speech_config(cmtspeech_nokiamodem_t *priv, cmtspeech_event_t *event) { int res = 0; int frame_size; if (event->msg.speech_config_req.speech_data_stream) { /* case: call is started or updated */ priv->conf_sample_rate = event->msg.speech_config_req.sample_rate; priv->conf_data_length = CMTSPEECH_DATA_LENGTH_20MS; if (priv->conf_sample_rate == CMTSPEECH_SAMPLE_RATE_8KHZ) { frame_size = 160 * PCM_SAMPLE_SIZE; } else if (priv->conf_sample_rate == CMTSPEECH_SAMPLE_RATE_16KHZ) { frame_size = 320 * PCM_SAMPLE_SIZE; } else { TRACE_ERROR(DEBUG_PREFIX "Invalid sample rate (%u) in SPEECH_CONFIG_REQ.", event->msg.speech_config_req.sample_rate); /* FIXME: this error should be propagated so an error response * is sent back to peer */ frame_size = -1; priv->slot_size = 0; res = 1; } if (frame_size > 0) priv->slot_size = frame_size + CMTSPEECH_DATA_HEADER_LEN; } else { /* case: call terminated */ SOFT_ASSERT(event->msg.speech_config_req.speech_data_stream == 0); frame_size = 0; priv->slot_size = 0; TRACE_DEBUG(DEBUG_PREFIX "Parsing SPEECH_CONFIG_REQ, call terminated."); } /* note: DMA reconfiguration is needed in all cases, so * layout is marked as changed even in cases where * the frame size remains the same. */ event->msg.speech_config_req.layout_changed = true; if (priv_locked_bufdescs(priv, false) == 0) { /* note: If no buffers are currently locked by the application, * continue to execute the change immediately. This * action will cancel all pending DMA transfers (both UL * and DL), as well as reset the mmap area state. */ res = priv_setup_and_send_speech_config_reply(priv); } else { TRACE_IO(DEBUG_PREFIX "Buffer layout changed, but application is holding to %d locked buffers. Postponing SPEECH_CONFIG_RESP reply.", priv_locked_bufdescs(priv, true)); priv->speech_config_resp_pend = true; priv_invalidate_buffer_slots(priv); } return res; } static void priv_initialize_after_peer_reset(cmtspeech_nokiamodem_t *priv) { TRACE_IO(DEBUG_PREFIX "Peer reset, initializing local state."); priv->slot_size = 0; priv_setup_driver_bufconfig(priv); cmtspeech_bc_state_change_reset(priv); priv_reset_wakeline_state(priv); } /** * Handles an incoming SPEECH_CONFIG_REQ message. * * See also priv_handle_reset_response() and priv_send_reset(). */ static int priv_handle_reset_conn_req(cmtspeech_nokiamodem_t *priv) { cmtspeech_cmd_t respcmd; int res = -1, i; i = cmtspeech_msg_encode_reset_conn_resp(&respcmd); SOFT_ASSERT(i == CMTSPEECH_CTRL_LEN); i = priv_write(priv, respcmd); if (i == CMTSPEECH_CTRL_LEN) { res = 0; } /* step: Reset driver state. See notes in priv_send_reset(). * As reset has been initiated by CMT, we can close * the wakeline already at this point. */ priv_initialize_after_peer_reset(priv); return res; } static int priv_init_bufconfig_for_test_ramp_ping(cmtspeech_nokiamodem_t *priv, uint8_t ramplen) { int res = 0; TRACE_DEBUG(DEBUG_PREFIX "Initializing driver for TEST_RAMP_PING (ramplen %u words).", ramplen); /* note: in case DMA has not been setup yet, do it now with * the test ramp parameters (possible race conditions * between subsequent new SPEECH_CONFIG_REQ messages * are not handled) */ unsigned int new_slot_size = CMTSPEECH_DATA_HEADER_LEN + ramplen * 4; if (priv->slot_size != new_slot_size) { priv->slot_size = new_slot_size; res = priv_setup_driver_bufconfig(priv); if (res < 0) return res; } return res; } /** * Handles an incoming TEST_RAMP_PING message. */ static int priv_handle_test_ramp_ping(cmtspeech_nokiamodem_t *priv, const cmtspeech_cmd_t cmd) { cmtspeech_cmd_t respcmd; int res = 0, i; uint8_t channel, replychannel, rampstart, ramplen; const unsigned int ul_slot = 0; uint8_t *slotbuf = priv->d.buf + priv->d.tx_offsets[ul_slot]; SOFT_ASSERT(cmtspeech_msg_get_domain(cmd) == CMTSPEECH_DOMAIN_CONTROL); SOFT_ASSERT(cmtspeech_msg_get_type(cmd) == CMTSPEECH_TEST_RAMP_PING); cmtspeech_msg_decode_test_ramp_ping(cmd, &channel, &replychannel, &rampstart, &ramplen); TRACE_IO(DEBUG_PREFIX "Handling inbound TEST_RAMP_PING (ch:%u, replych:%u, start-val:0x%02x, ramplen %u words).", channel, replychannel, rampstart, ramplen); res = priv_acquire_wakeline(priv, WAKELINE_TEST_RAMP_PING); SOFT_ASSERT(res == 0); res = cmtspeech_msg_encode_ul_data_header(slotbuf, 4, 0xffff, CMTSPEECH_DATA_LENGTH_NONE, CMTSPEECH_SAMPLE_RATE_NONE, CMTSPEECH_DATA_TYPE_INVALID); SOFT_ASSERT(res == CMTSPEECH_DATA_HEADER_LEN); /* note: override some UL_SPEECH_DATA_FRAME header bits */ slotbuf[BYTE1] = ramplen; slotbuf[BYTE2] = 0x80; res = priv_init_bufconfig_for_test_ramp_ping(priv, ramplen); if (res < 0) return res; SOFT_ASSERT(priv->slot_size == CMTSPEECH_DATA_HEADER_LEN + (unsigned int)ramplen * 4); /* step: generate the ramp */ slotbuf += 4; for(i = 0; i < ramplen*4; i++) slotbuf[i] = rampstart++; /* notify driver that slot '0' is ready for sending */ res = priv_msg_encode_driver_message(&respcmd, CS_COMMAND(CS_TX_DATA_READY), ul_slot & CMD_PARAM_MASK); if (res == CMTSPEECH_CTRL_LEN) res = priv_write(priv, respcmd); if (res == CMTSPEECH_CTRL_LEN) return 0; return -1; } /** * Returns diff between the buffer position, to which hardware driver * will write next (reported via mmap segment), and the application * buffer position. * * In normal conditions, the delay should vary between zero * and 'DL_SLOTS-1'. */ static inline int priv_rx_hw_delay(cmtspeech_nokiamodem_t *priv) { struct cs_mmap_config_block *mmap_cfg = (struct cs_mmap_config_block *)priv->d.buf; return ((mmap_cfg->rx_ptr_boundary + mmap_cfg->rx_ptr - priv->rx_ptr_appl) % mmap_cfg->rx_ptr_boundary); } /** * Returns the number of available RX buffers. * * Note that this number does not include possible frames * queued in the driver (see priv_rx_hw_delay()). */ static inline int priv_rx_ptr_avail(const cmtspeech_nokiamodem_t *priv) { struct cs_mmap_config_block *mmap_cfg = (struct cs_mmap_config_block *)priv->d.buf; return ((mmap_cfg->rx_ptr_boundary + priv->rx_ptr_hw - priv->rx_ptr_appl) % mmap_cfg->rx_ptr_boundary); } static void handle_inbound_rx_data_received(cmtspeech_nokiamodem_t *priv, const cmtspeech_cmd_t cmd, int *flags) { int last_slot; int next_slot; TRACE_DEBUG(DEBUG_PREFIX "internal event DL_DATA_RECEIVED."); /* step: queue event for application */ *flags |= CMTSPEECH_EVENT_DL_DATA; priv->rx_ptr_hw = (CS_PARAM_MASK & cmd.d.cmd); if (priv->rx_ptr_appl < 0) priv->rx_ptr_appl = priv->rx_ptr_hw; /* step: perform overrun checking */ last_slot = (priv->rx_ptr_hw) % DL_SLOTS; next_slot = (last_slot + 1) % DL_SLOTS; if ((priv->d.flags & DRIVER_FEAT_ROLLING_RX_PTR) && priv_rx_hw_delay(priv) >= DL_SLOTS) { struct cs_mmap_config_block *mmap_cfg = (struct cs_mmap_config_block *)priv->d.buf; /* xrun case 1: * We have not reacted to driver wakeups fast enough and * driver has overrun the rx buffer at this point. */ TRACE_INFO(DEBUG_PREFIX "DL buffer overrun (mmaphw %d, hw %d, appl %d, slot %u, count %u, hwdelay %d).", mmap_cfg->rx_ptr, priv->rx_ptr_hw, priv->rx_ptr_appl, last_slot, DL_SLOTS, priv_rx_hw_delay(priv)); priv->dlbufdesc[last_slot].flags |= BUF_XRUN; *flags |= CMTSPEECH_EVENT_XRUN; } if (priv->dlbufdesc[next_slot].flags & BUF_LOCKED) { /* xrun case 2: * The slot, to which driver will write next, is still owned * by application - overrun is not certain, but data * coherency cannot be guaranteed, so reporting as an XRUN */ TRACE_INFO(DEBUG_PREFIX "possible DL buffer overrun (hw %d, appl %d, slot %u, count %u).", priv->rx_ptr_hw, priv->rx_ptr_appl, next_slot, DL_SLOTS); priv->dlbufdesc[next_slot].flags |= BUF_XRUN; *flags |= CMTSPEECH_EVENT_XRUN; } if (priv->dlbufdesc[last_slot].flags & BUF_LOCKED) { /* xrun case 3: * The slot last used by driver is still owned by application */ TRACE_INFO(DEBUG_PREFIX "DL buffer overrun (hw %d, appl %d, slot %u, count %u).", priv->rx_ptr_hw, priv->rx_ptr_appl, last_slot, DL_SLOTS); /* note: mark the overrun buffer and raise an event bit */ priv->dlbufdesc[last_slot].flags |= BUF_XRUN; *flags |= CMTSPEECH_EVENT_XRUN; } /* step: reenable UL if paused (as DL path is now working) */ if (priv->ul_errors > 0) { priv->ul_errors = 0; TRACE_IO(DEBUG_PREFIX "DL frame received, reactivating UL transfers."); } } /** * Processes messages sent by the modem and internal events * generated by the driver. The messages are parsed and * stored to an internal event queue. Application can fetch * the events with cmtspeech_read_event(). * * @see cmtspeech_check_pending(), cmtspeech_read_event() * * @return 1 if events available, 0 if not, or a negative error code */ static int handle_inbound_control_message(cmtspeech_nokiamodem_t *priv, const cmtspeech_cmd_t cmd, int *flags) { int res = 0; int type = cmtspeech_msg_get_type(cmd); int channel = cmtspeech_msg_get_domain(cmd); TRACE_DEBUG(DEBUG_PREFIX "handling bytes %02X:%02X:%02X:%02X, on channel %d.", cmd.d.buf[0], cmd.d.buf[1], cmd.d.buf[2], cmd.d.buf[3], cmtspeech_msg_get_domain(cmd)); if (channel == CMTSPEECH_DOMAIN_CONTROL) { cmtspeech_event_t cmtevent; int retval; TRACE_IO(DEBUG_PREFIX "read bytes %02X:%02X:%02X:%02X, control channel message (%s).", cmd.d.buf[0], cmd.d.buf[1], cmd.d.buf[2], cmd.d.buf[3], cmtspeech_msg_type_to_string(cmd)); retval = cmtspeech_bc_handle_command(&priv->bcstate, priv, cmd, &cmtevent); if (retval != 0) { res = -1; } else { switch(type) { case CMTSPEECH_RESET_CONN_REQ: priv_handle_reset_conn_req(priv); break; case CMTSPEECH_RESET_CONN_RESP: priv_handle_reset_response(priv); break; case CMTSPEECH_SSI_CONFIG_RESP: priv_handle_ssi_config_resp(priv); break; case CMTSPEECH_SPEECH_CONFIG_REQ: priv_handle_speech_config(priv, &cmtevent); break; case CMTSPEECH_TIMING_CONFIG_NTF: { /* note: copy the kernel timestamp for the message */ struct timespec *s = (struct timespec *)(priv->d.buf + priv->d.tstamp_rx_ctrl_offset); memcpy(&cmtevent.msg.timing_config_ntf.tstamp, s, sizeof(*s)); } break; case CMTSPEECH_UPLINK_CONFIG_NTF: break; case CMTSPEECH_TEST_RAMP_PING: priv_handle_test_ramp_ping(priv, cmd); break; default: TRACE_ERROR(DEBUG_PREFIX "ERROR: unknown control message of type %d.", type); SOFT_ASSERT(false); } ONDEBUG( struct timespec *s = (struct timespec *)(priv->d.buf + priv->d.stamp_rx_ctrl_offset); if (priv->d.stamp_rx_ctrl_offset > 0) cmtspeech_trace_message(CMTSPEECH_TRACE_DEBUG, DEBUG_PREFIX " control message received at %ld:%ldns.", s->tv_sec, s->tv_nsec) ); cmtspeech_bc_complete_event_processing(&priv->bcstate, priv, &cmtevent); if (type != CMTSPEECH_TEST_RAMP_PING) { priv_queue_control_event(priv, &cmtevent); *flags |= CMTSPEECH_EVENT_CONTROL; res = 1; } } } else if (channel == CMTSPEECH_DOMAIN_INTERNAL) { /* note: internal messages are generated by the backend * and are not sent by the CMT; they are primarily * used for wake-ups */ switch(type) { case CS_COMMAND(CS_RX_DATA_RECEIVED): handle_inbound_rx_data_received(priv, cmd, flags); res = 1; break; #ifdef CS_TX_DATA_SENT case CS_COMMAND(CS_TX_DATA_SENT): TRACE_DEBUG(DEBUG_PREFIX "internal event UL_DATA_SENT."); break; #endif case CS_COMMAND(CS_ERROR): { cmtspeech_event_t cmtevent; TRACE_ERROR(DEBUG_PREFIX "ERROR: ERROR indication %d received, reseting state", cmd.d.cmd & CMD_PARAM_MASK); cmtevent.msg_type = CMTSPEECH_EVENT_RESET; cmtevent.prev_state = priv->bcstate.proto_state; cmtevent.msg.reset_done.cmt_sent_req = 0; priv_initialize_after_peer_reset(priv); cmtevent.state = priv->bcstate.proto_state; priv_queue_control_event(priv, &cmtevent); *flags |= CMTSPEECH_EVENT_CONTROL; res = 1; break; } default: TRACE_ERROR(DEBUG_PREFIX "ERROR: unknown control message of type %d (%02X:%02X:%02X:%02x).", type, cmd.d.buf[0], cmd.d.buf[1], cmd.d.buf[2], cmd.d.buf[3]); } } else res = -1; return res; } int cmtspeech_check_pending(cmtspeech_t *context, int *flags) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; cmtspeech_cmd_t cmd; int i, res = 0; if (!flags) return -1; *flags = 0; i = read(priv->d.fd, cmd.d.buf, CMTSPEECH_CTRL_LEN); if (i >= CMTSPEECH_CTRL_LEN) { res = handle_inbound_control_message(priv, cmd, flags); TRACE_DEBUG(DEBUG_PREFIX "read %d from cmtspeech device, handle res %d.", i, res); } else TRACE_ERROR(DEBUG_PREFIX "read returned %d.", i); return res; } int cmtspeech_read_event(cmtspeech_t *context, cmtspeech_event_t *event) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; return priv_dequeue_control_event(priv, event); } int cmtspeech_state_change_call_status(cmtspeech_t *context, bool state) { return cmtspeech_bc_state_change_call_status(context, state); } int cmtspeech_state_change_call_connect(cmtspeech_t *context, bool state) { return cmtspeech_bc_state_change_call_connect(context, state); } int cmtspeech_state_change_error(cmtspeech_t *context) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; return priv_send_reset(priv); } #if PROTOCOL_SUPPORT_SAMPLE_SWAP /** * In-place swap of every 32bit word in buffer 'buf' (0xaabbccdd * is swapped to 0xccddaabb). */ static void priv_inplace_halfword_swap(uint8_t *buf, int n) { uint32_t *wbuf = (uint32_t*)buf; int i; assert(n % 4 == 0); for(i = 0; i < n / 4; i++) { uint32_t tmp = *wbuf; *wbuf = (tmp << 16) | (tmp >> 16); ++wbuf; } return; } #endif /* PROTOCOL_SUPPORT_SAMPLE_SWAP */ /** * Returns the RX slot to give out to application * * If application has fallen behind the driver, negative * error code is returned for each missed slot. */ static int priv_rx_appl_slot(cmtspeech_nokiamodem_t *priv) { if (priv->d.flags & DRIVER_FEAT_ROLLING_RX_PTR) { struct cs_mmap_config_block *mmap_cfg = (struct cs_mmap_config_block *)priv->d.buf; int avail = priv_rx_ptr_avail(priv); int delay = priv_rx_hw_delay(priv); if (avail == mmap_cfg->rx_ptr_boundary - 1) { TRACE_INFO(DEBUG_PREFIX "no frames available (hw %d, appl %d, avail %d, count %u, boundary %u).", priv->rx_ptr_hw, priv->rx_ptr_appl, avail, DL_SLOTS, mmap_cfg->rx_ptr_boundary); return -ENODATA; } else if (delay >= DL_SLOTS) { TRACE_INFO(DEBUG_PREFIX "late appl wakeup (hw %d, appl %d, delay %d, count %u, boundary %u).", priv->rx_ptr_hw, priv->rx_ptr_appl, delay, DL_SLOTS, mmap_cfg->rx_ptr_boundary); return -EPIPE; } } return priv->rx_ptr_appl % DL_SLOTS; } static void priv_bump_rx_ptr_appl(cmtspeech_nokiamodem_t *priv) { struct cs_mmap_config_block *mmap_cfg = (struct cs_mmap_config_block *)priv->d.buf; ++priv->rx_ptr_appl; if (priv->d.flags & DRIVER_FEAT_ROLLING_RX_PTR) priv->rx_ptr_appl %= mmap_cfg->rx_ptr_boundary; else priv->rx_ptr_appl %= DL_SLOTS; } /** * Resync buffer pointers after an RX buffer overrun. * Returns a valid */ static void priv_rx_ptr_appl_handle_xrun(cmtspeech_nokiamodem_t *priv) { assert(priv->d.flags & DRIVER_FEAT_ROLLING_RX_PTR); TRACE_IO(DEBUG_PREFIX "DL xrun, reset hw/appl at %d", priv->rx_ptr_hw); priv->rx_ptr_appl = priv->rx_ptr_hw; } int cmtspeech_dl_buffer_acquire(cmtspeech_t *context, cmtspeech_buffer_t **buf) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; nokiamodem_buffer_desc_t *desc; uint16_t frame_counter; uint8_t spc_flags, data_length, data_type, sample_rate, codec_sample_rate; int res; int slot; if (priv->rx_ptr_appl < 0) return -EINVAL; slot = priv_rx_appl_slot(priv); if (slot == -EPIPE) { priv_rx_ptr_appl_handle_xrun(priv); slot = priv->rx_ptr_appl % DL_SLOTS; } else if (slot < 0) { SOFT_ASSERT(slot == -ENODATA); return slot; } assert(slot >= 0); assert(slot < DL_SLOTS); desc = &priv->dlbufdesc[slot]; /* note: must be bumped before the following checks * that might return with -EINVAL */ priv_bump_rx_ptr_appl(priv); if (desc->flags & BUF_INVALID) return -EINVAL; if (buf == NULL) return -EINVAL; SOFT_ASSERT(desc == &priv->dlbufdesc[slot]); res = cmtspeech_msg_decode_dl_data_header_v5(desc->bd.data, CMTSPEECH_DATA_HEADER_LEN, &frame_counter, &spc_flags, &data_length, &sample_rate, &codec_sample_rate, &data_type); SOFT_ASSERT(res == 0); TRACE_DEBUG(DEBUG_PREFIX "DL frame received (hw %d, appl %d, slot %u, %u bytes, frame-counter %u, type %d):", priv->rx_ptr_hw, priv->rx_ptr_appl, slot, priv->slot_size, frame_counter, data_type); /* note: decode frame header and fill dlbufdesc fields appropriately */ desc->bd.frame_flags = CMTSPEECH_DATA_TYPE_VALID; desc->bd.spc_flags = spc_flags; /* note: reserved bits 0:4 are used for sampling rate info */ desc->bd.reserved[0] = codec_sample_rate | (sample_rate << 2); desc->flags |= BUF_LOCKED; *buf = &(desc->bd); #if PROTOCOL_SUPPORT_SAMPLE_SWAP if (priv->bcstate.sample_layout == CMTSPEECH_SAMPLE_LAYOUT_SWAPPED_LE) { uint8_t *mmap_slot; mmap_slot = priv->d.buf + priv->d.rx_offsets[slot]; /* note: Copy and swap frames from mmap area to a heap buffer. The buffer * descriptor given to application points to the heap * buffer. */ SOFT_ASSERT(desc->bd.data != mmap_slot); memcpy(desc->bd.data, mmap_slot, desc->bd.count); if (desc->bd.pcount > 0) priv_inplace_halfword_swap(desc->bd.payload, desc->bd.pcount); } #endif /* note: some fields are set at buffer setup time in * priv_setup_driver_bufconfig() */ SOFT_ASSERT(desc->bd.type == CMTSPEECH_BUFFER_TYPE_PCM_S16_LE); SOFT_ASSERT(desc->bd.count == (int)priv->slot_size); SOFT_ASSERT(desc->bd.pcount == desc->bd.count - CMTSPEECH_DATA_HEADER_LEN); SOFT_ASSERT(desc->bd.size == desc->bd.count); SOFT_ASSERT(desc->bd.payload == desc->bd.data + CMTSPEECH_DATA_HEADER_LEN); SOFT_ASSERT(desc->bd.index == slot); if (priv->bcstate.proto_state == CMTSPEECH_STATE_TEST_RAMP_PING_ACTIVE) { cmtspeech_bc_test_sequence_received(&priv->bcstate); } return 0; } int cmtspeech_dl_buffer_release(cmtspeech_t *context, cmtspeech_buffer_t *buf) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; int ret = 0; SOFT_ASSERT(buf != NULL); if ((priv->dlbufdesc[buf->index].flags & BUF_LOCKED) == 0) return -ENOENT; /* note: special case handling if layout change is pending */ if (priv->speech_config_resp_pend == true) { priv_drvbuf_layout_change_buffer_released(priv, priv->dlbufdesc, buf); SOFT_ASSERT(priv->dlbufdesc[buf->index].flags == 0); } else { SOFT_ASSERT(priv->dlbufdesc[buf->index].bd.data == buf->data); SOFT_ASSERT(priv->dlbufdesc[buf->index].bd.payload == buf->payload); priv->dlbufdesc[buf->index].flags &= ~BUF_LOCKED; if (priv->dlbufdesc[buf->index].flags & BUF_XRUN) { priv->dlbufdesc[buf->index].flags &= ~BUF_XRUN; ret = -EPIPE; } } return ret; } cmtspeech_buffer_t *cmtspeech_dl_buffer_find_with_data(cmtspeech_t *context, uint8_t *data) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; int i; for(i = 0; i < DL_SLOTS; i++) { if (priv->dlbufdesc[i].bd.data == data) return &priv->dlbufdesc[i].bd; } return NULL; } cmtspeech_buffer_t *cmtspeech_dl_buffer_find_with_payload(cmtspeech_t *context, uint8_t *payload) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; int i; for(i = 0; i < DL_SLOTS; i++) { if (priv->dlbufdesc[i].bd.payload == payload) return &priv->dlbufdesc[i].bd; } return NULL; } int cmtspeech_test_data_ramp_req(cmtspeech_t *context, uint8_t rampstart, uint8_t ramplen) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; int res; res = priv_init_bufconfig_for_test_ramp_ping(priv, ramplen); if (res < 0) return res; res = priv_acquire_wakeline(priv, WAKELINE_TEST_RAMP_PING); if (res < 0) return res; return cmtspeech_bc_test_data_ramp_req(&priv->bcstate, context, priv->d.fd, CMTSPEECH_DOMAIN_CONTROL, CMTSPEECH_DOMAIN_DATA, rampstart, ramplen); } int cmtspeech_send_timing_request(cmtspeech_t *context) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; return cmtspeech_bc_send_timing_request(&priv->bcstate, context, priv->d.fd); } int cmtspeech_send_ssi_config_request(cmtspeech_t *context, bool state) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; if (state == true) { /* step: enable SSI wakeline */ priv_acquire_wakeline(priv, WAKELINE_CALL); } return cmtspeech_bc_send_ssi_config_request(&priv->bcstate, context, priv->d.fd, state); } int cmtspeech_ul_buffer_acquire(cmtspeech_t *context, cmtspeech_buffer_t **buf) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; nokiamodem_buffer_desc_t *desc; if (cmtspeech_is_active(context) != true) return -EINVAL; if (priv->ul_slot_app < 0) return -EINVAL; desc = &priv->ulbufdesc[priv->ul_slot_app]; SOFT_ASSERT(desc == &priv->ulbufdesc[priv->ul_slot_app]); if (desc->flags & BUF_INVALID) return -EINVAL; if (desc->flags & BUF_LOCKED) return -ENOBUFS; if (buf == NULL) return -EINVAL; desc->bd.frame_flags = 0; desc->flags |= BUF_LOCKED; /* note: some fields are set at buffer setup time in * priv_setup_driver_bufconfig() */ SOFT_ASSERT(desc->bd.type == CMTSPEECH_BUFFER_TYPE_PCM_S16_LE); SOFT_ASSERT(desc->bd.count == (int)priv->slot_size); SOFT_ASSERT(desc->bd.pcount == desc->bd.count - CMTSPEECH_DATA_HEADER_LEN); SOFT_ASSERT(desc->bd.size == desc->bd.count); SOFT_ASSERT(desc->bd.payload == desc->bd.data + CMTSPEECH_DATA_HEADER_LEN); SOFT_ASSERT(desc->bd.index == priv->ul_slot_app); *buf = &priv->ulbufdesc[priv->ul_slot_app].bd; ++priv->ul_slot_app; priv->ul_slot_app %= UL_SLOTS; return 0; } int cmtspeech_ul_buffer_release(cmtspeech_t *context, cmtspeech_buffer_t *buf) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; cmtspeech_cmd_t msg; int res; SOFT_ASSERT(cmtspeech_protocol_state(context) == CMTSPEECH_STATE_ACTIVE_DLUL); if (buf == NULL) return -EINVAL; SOFT_ASSERT(buf->index >= 0); /* note: special case handling if layout change is pending */ if (priv->speech_config_resp_pend == true) { priv_drvbuf_layout_change_buffer_released(priv, priv->ulbufdesc, buf); SOFT_ASSERT(priv->ulbufdesc[buf->index].flags == 0); return 0; } SOFT_ASSERT(priv->ulbufdesc[buf->index].bd.data == buf->data); SOFT_ASSERT(priv->ulbufdesc[buf->index].bd.payload == buf->payload); if (priv->ul_errors >= MAX_UL_ERRORS_PAUSE) { if (priv->bcstate.io_errors > 0) { /* note: with some CMT firmware releases, the uplink DMA transfers may fail due to loss of network coverage. To make sure we don't return -EIO unless the connection is really broken, we use 'io_errors' count as a trigger. */ res = -EIO; } else { /* note: if enough consecutive errors, do not send more * UL frames to the modem */ res = -EBUSY; } } /* note: only send frames when protocol state allows it */ else if (cmtspeech_protocol_state(context) == CMTSPEECH_STATE_ACTIVE_DLUL) { static int16_t ul_counter = 0; TRACE_DEBUG(DEBUG_PREFIX "filling UL slot %u, size %u.", buf->index & CMD_PARAM_MASK, buf->pcount); #if PROTOCOL_SUPPORT_SAMPLE_SWAP if (priv->bcstate.sample_layout == CMTSPEECH_SAMPLE_LAYOUT_SWAPPED_LE) priv_inplace_halfword_swap(buf->payload, buf->pcount); #endif res = cmtspeech_msg_encode_ul_data_header(buf->data, CMTSPEECH_DATA_HEADER_LEN, ul_counter, priv->conf_data_length, priv->conf_sample_rate, buf->frame_flags); SOFT_ASSERT(res == CMTSPEECH_DATA_HEADER_LEN); /* note: send a CS_CS_UL_DATA_READY message to the driver */ priv_msg_encode_driver_message(&msg, CS_COMMAND(CS_TX_DATA_READY), buf->index & CMD_PARAM_MASK); res = priv_write_data(priv, msg); if (res == CMTSPEECH_CTRL_LEN) { ul_counter += 4; /* increment of 4*5ms */ res = 0; } else { TRACE_IO("UL frame send failed with %d (%d: %s)", res, errno, strerror(errno)); if (res < 0 && errno == EBUSY) { res = -EBUSY; ++priv->ul_errors; } else { /* note: SSI subsystem in invalid state, stop sending more UL * frames immediately */ res = -EINVAL; priv->ul_errors = MAX_UL_ERRORS_PAUSE; } } } else { SOFT_ASSERT(cmtspeech_protocol_state(context) != CMTSPEECH_STATE_ACTIVE_DLUL); res = -EPIPE; } priv->ulbufdesc[buf->index].flags &= ~BUF_LOCKED; return res; } const char* cmtspeech_backend_name(cmtspeech_t* context) { return CMTSPEECH_BACKEND_ID; } int cmtspeech_backend_message(cmtspeech_t *self, int type, int args, ...) { /* no-op */ return -1; } int cmtspeech_buffer_codec_sample_rate(cmtspeech_buffer_t *context) { /* note: bits 0:1 of the first reserved slot are used for sample rate */ return context->reserved[0] & 3; } int cmtspeech_buffer_sample_rate(cmtspeech_buffer_t *context) { /* note: bits 2:3 of the first reserved slot are used for sample rate */ return (context->reserved[0] >> 2) & 3; } cmtspeech_bc_state_t *cmtspeech_bc_state_object(cmtspeech_t *context) { cmtspeech_nokiamodem_t *priv = (cmtspeech_nokiamodem_t*)context; return &priv->bcstate; } libcmtspeechdata-2.1.1+git20160721~8efc468/cmtspeech_null.c000066400000000000000000000106471112705070200227730ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech_null.c * * A libcmtspeechdata backend implementation that demonstrates * how to add a new modem backend to the build scripts. This * 'null' backend does not do anything (it can be built, but * has not functionality). * * See 'dummy-backend/' for a backend that simulates a modem. */ #include #include "cmtspeech.h" /* Interfaces: Core I/O * -------------------- */ void cmtspeech_init(void) { } cmtspeech_t* cmtspeech_open(void) { return NULL; } int cmtspeech_close(cmtspeech_t *context) { return -1; } int cmtspeech_descriptor(cmtspeech_t *context) { return -1; } int cmtspeech_check_pending(cmtspeech_t *context, int *flags) { return -1; } int cmtspeech_read_event(cmtspeech_t *context, cmtspeech_event_t *event) { return -1; } /* Interfaces: Event parsing * ------------------------- */ int cmtspeech_event_to_state_transition(const cmtspeech_t *context, const cmtspeech_event_t *event) { return CMTSPEECH_TR_INVALID; } /* Interfaces: Runtime configuration * --------------------------------- */ int cmtspeech_set_wb_preference(cmtspeech_t *context, bool enabled) { return -1; } /* Interfaces: State management * ---------------------------- */ int cmtspeech_protocol_state(cmtspeech_t* context) { return CMTSPEECH_STATE_INVALID; } bool cmtspeech_is_ssi_connection_enabled(cmtspeech_t *context) { return false; } bool cmtspeech_is_active(cmtspeech_t *context) { return false; } int cmtspeech_state_change_call_status(cmtspeech_t *context, bool state) { return false; } int cmtspeech_state_change_call_connect(cmtspeech_t *context, bool state) { return false; } int cmtspeech_state_change_error(cmtspeech_t *context) { return false; } /* Interfaces: Buffer management * -------------------------------------- */ int cmtspeech_ul_buffer_acquire(cmtspeech_t *context, cmtspeech_buffer_t **buf) { return -EINVAL; } int cmtspeech_ul_buffer_release(cmtspeech_t *context, cmtspeech_buffer_t *buf) { return -EINVAL; } int cmtspeech_dl_buffer_acquire(cmtspeech_t *context, cmtspeech_buffer_t **buf) { return -EINVAL; } int cmtspeech_dl_buffer_release(cmtspeech_t *context, cmtspeech_buffer_t *buf) { return -EINVAL; } cmtspeech_buffer_t *cmtspeech_dl_buffer_find_with_data(cmtspeech_t *context, uint8_t *data) { return NULL; } cmtspeech_buffer_t *cmtspeech_dl_buffer_find_with_payload(cmtspeech_t *context, uint8_t *payload) { return NULL; } /* Interfaces: Implementation version information * ---------------------------------------------------- */ const char* cmtspeech_version_str(void) { return VERSION; } int cmtspeech_protocol_version(void) { return LIBCMTSPEECHDATA_PROTOCOL_VERSION; } /* Interfaces: Access to backend specific functionality * ---------------------------------------------------- */ const char* cmtspeech_backend_name(cmtspeech_t* context) { return "null"; } int cmtspeech_backend_message(cmtspeech_t *self, int type, int args, ...) { return -1; } int cmtspeech_buffer_codec_sample_rate(cmtspeech_buffer_t *context) { return CMTSPEECH_SAMPLE_RATE_NONE; } int cmtspeech_buffer_sample_rate(cmtspeech_buffer_t *context) { return CMTSPEECH_SAMPLE_RATE_NONE; } /* Interfaces: Low level message handling * -------------------------------------- */ int cmtspeech_send_timing_request(cmtspeech_t *context) { return -1; } int cmtspeech_send_ssi_config_request(cmtspeech_t *context, bool active) { return -1; } /* Interfaces: Test interface * -------------------------- */ int cmtspeech_test_data_ramp_req(cmtspeech_t *context, uint8_t rampstart, uint8_t ramplen) { return -1; } libcmtspeechdata-2.1.1+git20160721~8efc468/configure.ac000066400000000000000000000076671112705070200221200ustar00rootroot00000000000000dnl Copyright (C) 2008,2010,2011 Nokia Corporation dnl Contact: Kai Vehmanen dnl Licensed under LGPL. See file COPYING. dnl dnl ref: http://www.gnu.org/software/autoconf/manual/autoconf.info.gz dnl AC_PREREQ(2.57) dnl information on the package dnl --------------------------- AC_INIT([libcmtspeechdata], [2.1.1]) AC_CONFIG_SRCDIR([cmtspeech.h]) AM_INIT_AUTOMAKE([foreign]) AM_MAINTAINER_MODE VERSION_MAJOR=`echo $VERSION |cut -f1 -d.` VERSION_LIBRARY_API=`echo $VERSION |cut -f2 -d.` VERSION_MINOR=`echo $VERSION |cut -f3 -d.` VERSION_PROTOCOL=2 AC_SUBST(VERSION_MAJOR) AC_SUBST(VERSION_LIBRARY_API) AC_SUBST(VERSION_MINOR) AC_SUBST(VERSION_PROTOCOL) dnl checks for programs dnl ------------------- AC_PROG_CC AC_PROG_INSTALL AC_PROG_CPP AC_CHECK_TOOL(AR, ar, ar) AC_CHECK_TOOL(LD, ld, ld) AC_PROG_LIBTOOL AM_PROG_CC_C_O dnl check for debugging options dnl ------------------- AC_MSG_CHECKING([whether to enable asserts and other debug facilities]) AC_ARG_ENABLE([extra-debug], AC_HELP_STRING([--disable-extra-debug], [Disable asserts and debug traces]), AC_MSG_RESULT([no]) AC_DEFINE(NDEBUG, 1, [Define to 1 if debug facilities should be disabled]), AC_MSG_RESULT([yes])) dnl check for doxygen dnl ----------------- AC_ARG_ENABLE(docs, AC_HELP_STRING([--enable-docs], [Build DOXYGEN documentation (requires Doxygen)]), enable_docs=$enableval,enable_docs=auto) AC_PATH_PROG(DOXYGEN, doxygen, no) AC_MSG_CHECKING([whether to build Doxygen documentation]) if test x$DOXYGEN = xno ; then have_doxygen=no else have_doxygen=yes fi if test x$enable_docs = xauto ; then if test x$have_doxygen = xno ; then enable_docs=no else enable_docs=yes fi fi if test x$enable_docs = xyes; then if test x$have_doxygen = xno; then AC_MSG_ERROR([Building Doxygen docs explicitly required, but Doxygen not found]) else AC_MSG_RESULT(yes) fi else AC_MSG_RESULT(no) fi AM_CONDITIONAL(DOXYGEN_DOCS_ENABLED, test x$enable_docs = xyes) AC_SUBST(DOXYGEN) dnl checks for libraries dnl -------------------- PKG_CHECK_MODULES([CHECK], [check >= 0.9.4]) PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.0]) AC_SUBST(DBUS_CFLAGS) AC_SUBST(DBUS_LIBS) dnl note: this affects the main library build (the dummy dnl library is built always under dummy-backend/ ) default_backend="nokiamodem" AC_ARG_WITH([backend], AC_HELP_STRING([--with-backend=BACKEND], [select which backend to use]), [ case "$withval" in dummy) backend="dummy" ;; nokiamodem) backend="nokiamodem" ;; null) backend="null" ;; *) AC_MSG_ERROR([unsupported backend: $withval]) ;; esac ]) if test "x$backend" = "x" ; then backend="$default_backend" fi AM_CONDITIONAL(USE_BACKEND_DUMMY, [test "x$backend" = "xdummy"]) AM_CONDITIONAL(USE_BACKEND_NOKIAMODEM, [test "x$backend" = "xnokiamodem"]) AM_CONDITIONAL(USE_BACKEND_NULL, [test "x$backend" = "xnull"]) AC_MSG_RESULT([selecting default backend: $backend]) AC_ARG_ENABLE(nokiamodem-vdd2lock, AC_HELP_STRING([--enable-nokiamodem-vdd2lock], [nokiamodem: Utilize Maemo5 kernel interface for memory/vdd2 locking]), nokiamodem_vdd2lock=$enableval,nokiamodem_vdd2lock=no) if test "x$nokiamodem_vdd2lock" = "xyes" ; then AC_DEFINE(NOKIAMODEM_VDD2LOCK, 1, [Define to 1 if debug facilities should be disabled]) fi dnl checks for types dnl ---------------- dnl checks for structures dnl --------------------- AC_CHECK_HEADERS(stdio.h) AC_CHECK_HEADERS(sched.h sys/stat.h sys/mman.h) AC_CHECK_HEADERS(mcheck.h syslog.h) AC_CHECK_HEADERS(linux/cs-protocol.h) dnl checks for typedefs, structures, and compiler characteristics. dnl -------------------------------------------------------------- AC_C_CONST dnl output dnl ------ AC_CONFIG_FILES([ Makefile cmtspeech_config.h libcmtspeechdata.pc doc/Makefile doc/doxygen.cfg dummy-backend/Makefile ]) AC_OUTPUT libcmtspeechdata-2.1.1+git20160721~8efc468/doc/000077500000000000000000000000001112705070200203575ustar00rootroot00000000000000libcmtspeechdata-2.1.1+git20160721~8efc468/doc/Makefile.am000066400000000000000000000014121112705070200224110ustar00rootroot00000000000000# Copyright (C) 2008,2009,2010 Nokia Corporation # Contact: Kai Vehmanen # Licensed under LGPL. See file COPYING. # documentation rules # ------------------- EXTRA_DIST = doxygen.cfg.in libcmtspeechdata_api_docs_main.txt if DOXYGEN_DOCS_ENABLED DOXYGEN_LINE = $(DOXYGEN) doxygen.cfg install-data-local: if test -e doc-target-stamp ; then $(INSTALL) -d $(DESTDIR)${datarootdir}/doc/libcmtspeechdata-doc/html ; fi if test -e doc-target-stamp ; then $(INSTALL_DATA) html/* $(DESTDIR)${datarootdir}/doc/libcmtspeechdata-doc/html ; fi uninstall-local: rm -Rf $(DESTDIR)${datarootdir}/doc/libcmtspeechdata-doc/ else DOXYGEN_LINE = endif .PHONY : doc doc: doxygen.cfg touch doc-target-stamp $(DOXYGEN_LINE) clean-local: -rm -f doc-target-stamp -rm -rf html latexlibcmtspeechdata-2.1.1+git20160721~8efc468/doc/README-devel.txt000066400000000000000000000051361112705070200231570ustar00rootroot00000000000000************************************* Developer README for libcmtspeechdata ************************************* Copyright (C) 2009,2010 Nokia Corporation. All rights reserved. Introduction ============ This package provides the "libcmtspeechdata" library. Libcmtspeechdata provides an application interface for implementing the speech data path for cellular voice calls. The library depends on other components for setting up and managing the call signaling path. This README file provides information for developers. See also the main package README (part of the source tree). API: Developer's guide to libcmtspeechdata interfaces ===================================================== See the API documentation in: - source-tree libcmtspeechdata/doc/libcmtspeechdata_api_docs_main.txt - libcmtspeehcdata-doc debian package: /usr/share/doc/libcmtspeechdata-doc/html/ Internals: Developer's guide to libcmtspeechdata internals ========================================================== This section documents issues related to how libcmtspeechdata, and the various library backends, are implemented. It is meant for developers that are modifying, or otherwise need to understand the internals of, libcmtspeechdata. Internals: Code layout ---------------------- 'cmtspeech_*.[ch]' Sources for the public library. 'sal_*.[ch]' Library sources with legay file prefix (library was formely named the SSI Audio Library (SAL)). Internals: Resource allocation in 'nokiamodem' backend ------------------------------------------------------ When a library instance is opened with cmtspeech_open(), the backend will open the /dev/cmt_speech kernel device. The SSI control channel for CMT Speech Data protocol is opened. Also memory for buffer transfer is allocated at this point. The resources allocated in cmtspeech_open() are freed only when the library instance is closed with cmtspeech_close(). Internals: The libcmtspeechdata backend interface ------------------------------------------------- The library backends implement the public interface defined in cmtspeech.h file. To avoid unnecessary code duplication, some common helper functions for implementing cmtspeech.h are available in cmtspeech_backend_common.h. Also the message decoding/encoding interface provided by cmtspeech_msgs.h should be used by all backends. Currently no dynamic mechanism is provided to select different backends. Instead, a separate version of the library is build for each backend. The library interface is the same, so if dynamic linking is used, it is possible to change to a different backend without recompiling the clients. libcmtspeechdata-2.1.1+git20160721~8efc468/doc/doxygen.cfg.in000066400000000000000000001334701112705070200231320ustar00rootroot00000000000000# Doxyfile 1.3.7 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "libcmtspeechdata library API" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @VERSION@ # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = . # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 2 levels of 10 sub-directories under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of source # files, where putting all generated files in the same directory would otherwise # cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, # Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en # (Japanese with English messages), Korean, Korean-en, Norwegian, Polish, Portuguese, # Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # This tag can be used to specify the encoding used in the generated output. # The encoding is not always determined by the language that is chosen, # but also whether or not the output is meant for Windows or non-Windows users. # In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES # forces the Windows encoding (this is the default for the Windows binary), # whereas setting the tag to NO uses a Unix-style encoding (the default for # all platforms other than Windows). USE_WINDOWS_ENCODING = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is used # as the annotated text. Otherwise, the brief description is used as-is. If left # blank, the following values are used ("$name" is automatically replaced with the # name of the entity): "The $name class" "The $name widget" "The $name file" # "is" "provides" "specifies" "contains" "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited # members of a class in the documentation of that class as if those members were # ordinary class members. Constructors, destructors and assignment operators of # the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explicit @brief command for a brief description. JAVADOC_AUTOBRIEF = YES # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = YES # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = \ libcmtspeechdata_api_docs_main.txt \ @top_srcdir@/cmtspeech.h # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp # *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm FILE_PATTERNS = *.c *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = NO # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = */test/* # The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories # that are symbolic links (a Unix filesystem feature) are excluded from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. INPUT_FILTER = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse the # parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. Note that this # option is superseded by the HAVE_DOT option below. This is only a fallback. It is # recommended to install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = YES # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = NO # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes that # lay further from the root node will be omitted. Note that setting this option to # 1 or 2 may greatly reduce the computation time needed for large code bases. Also # note that a graph may be further truncated if the graph's image dimensions are # not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). # If 0 is used for the depth value (the default), the graph is not depth-constrained. MAX_DOT_GRAPH_DEPTH = 0 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO libcmtspeechdata-2.1.1+git20160721~8efc468/doc/libcmtspeechdata_api_docs_main.txt000066400000000000000000000350431112705070200272660ustar00rootroot00000000000000/** @mainpage libcmtspeechdata API documentation Copyright (C) 2009,2010 Nokia Corporation. All rights reserved.

Table of contents

  • @ref sect_introduction
  • @ref sect_api_versioning
  • @ref sect_backends
  • @ref sect_instance_management
  • @ref sect_handling_events
  • @ref sect_passing_events
  • @ref sect_app_initiated_actions

@section sect_introduction Introduction Libcmtspeechdata provides an application interface for implementing the speech data path for cellular voice calls. The library depends on other components for setting up and managing the call signaling path. CMT is abbreviation of Cellular Modem Terminal, i.e. the cellular modem. APE refers to Application Engine, i.e. the processing environment where libcmtspeechdata is run. E.g. in Nokia N900, APE the TI OMAP3 processor. SSI refers to Synchronous Serial Interface, which is a serial bus found on TI OMAP application engines as well as on Nokia cellular modems. SSI is used as the low-level interface used to communicate between APE and CMT. This documentation covers the public interface of the library. It is meant for developers using libcmtspeechdata. @section sect_api_versioning API Versioning The libcmtspeechdata package version consist of components X.Y.Z. X reflects the major version number and is incremented for major architectural/design changes. Y reflects the library interface version and this is incremented every time the public API has been extended since the last release (and is reset to zero if X changes). Z reflects an update to the library implementation and/or applications distributed with the package (and is reset to zero if Y changes). Applications may query these versions at build time with (defined when including ): - LIBCMTSPEECHDATA_MAJOR - LIBCMTSPEECHDATA_PROTOCOL_VERSION - LIBCMTSPEECHDATA_API_VERSION - LIBCMTSPEECHDATA_MINOR_VERSION Or at runtime with: - cmtspeech_version_str() (returns a string) - cmtspeech_protocol_version() (returns an integer) @section sect_backends Library backend implementations The library may be built using different backends. Typically binary runtime packages will be available at least for the main hardware implementation, and one using a dummy backend (not talking to a real modem). The alternative implementations are called library backends. Currently available backends are: @subsection sect_backend_dummy Dummy A user-space implementation of the CMT Speech Data SSI protocol. @subsection sect_backend_nokiamodem Nokia Modem Implementation of the CMT Speech Data Backend interface for Nokia modems (e.g. Maemo5 / Nokia N900). See notes in the libcmtspeechdata README-devel.txt file in section "Internals: Resource allocation in Nokia Modem backend". @subsection sect_backend_null Null A null implementaton of library backend. Provides no functinality, but provides an example how to integrate new modem backends to the library. @section sect_instance_management Instance Management Before using any other library functions, application should call cmtspeech_init(). This function needs to be called once per application process startup. All other library functions operate on a given instance of the library. A new instance is created with cmtspeech_open(). Application should create the library instance at the earliest possible moment, preferably right after the cellular modem is powered up. The reason for this is that opening the device with cmtspeech_open() involves allocation of various resources (memory, opening the kernel device, etc), and thus it has non-deterministic execution time. Note that it is also possible to open the library instance even though the cellular modem is not yet fully functional. Similarly cmtspeech_close() should only be called when cellular modem is powered off (and no calls are no longer made), or in error cases (e.g. application has detected, perhaps via some other API, that modem has crashed/rebooted). @section sect_handling_events Handling library events Once library instance is open, application should monitor for possible events by polling (with e.g. poll() or select()) the file descriptor returned by cmtspeech_descriptor(). If the descriptor becomes readable, application should immediately call cmtspeech_check_pending(). Bitmask of available events is returned by cmtspeech_check_pending() via the 'int *flags' argument. If the returned bitmask includes CMTSPEECH_EVENT_CONTROL, a control event is available and may be fetched with cmtspeech_read_event(). The library maintains a fixed size queue for the control events, which can overflow if the application does not fetch the events in time. NOTE: As libcmtspeechdata does not have its own event loop, only those state changes, that are triggered by incoming messages from the modem, are reported as events. An event contains the following information: - the new protocol state (one of CMTSPEECH_STATE_* defined in cmtspeech.h) - ::cmtspeech_event_t field 'state' - the previous protocol state (CMTSPEECH_STATE_*) - ::cmtspeech_event_t field 'prev_state' - a copy of the protocol message that caused the state change - ::cmtspeech_event_t fields 'msg_type' and 'msg' Most applications should use cmtspeech_event_to_state_transition() to convert the event object to an enumerated state transition, and handle the result e.g. in a switch loop. Here is a list of state transitions reported by cmtspeech_event_to_state_transition(). Some of the events are purely informational, while some require specific actions from the application. @subsection TR_1 CMTSPEECH_TR_1_CONNECTED Triggering protocol message is CMTSPEECH_SSI_CONFIG_RESP. This event indicates that the cellular modem has acknowledged activation of the data path for speech frame exchange. The current SSI connection status can be queried at any time with cmtspeech_is_ssi_connection_enabled(). @subsection TR_2 CMTSPEECH_TR_2_DISCONNECTED Triggering protocol message is CMTSPEECH_SSI_CONFIG_RESP. This event indicates that the cellular modem has acknowledged deactivation of the data path for speech frame exchange. @subsection TR_3 CMTSPEECH_TR_3_DL_START Triggering protocol message is: CMTSPEECH_SPEECH_CONFIG_REQ This event is used by the cellular modem to initiate transfer of downlink speech frames (from network). After this message, application should be prepared to receive CMTSPEECH_EVENT_DATA events. After this event cmtspeech_is_active() will return true. @subsection TR_4 CMTSPEECH_TR_4_DL_STOP Triggering protocol message is: CMTSPEECH_SPEECH_CONFIG_REQ This event signals that call termination has started and the speech data stream has been closed. After this event cmtspeech_is_active() will return 'false'. Application should immediate release any uplink or downlink buffers it has acquired from the library. The protocol state cannot go from CONNECTED to DISCONNECTED until all speech buffers, acquired with cmtspeech_ul_buffer_acquire() and cmtspeech_dl_buffer_acquire(), have been released back to the library. Note that this event can occur in both ACTIVE_DL and ACTIVE_DLUL protocol states. @subsection TR_6 CMTSPEECH_TR_6_TIMING_UPDATE Triggering protocol message is: CMTSPEECH_TIMING_CONFIG_NTF Similar to CMTSPEECH_TR_7_TIMING_UPDATE (see @ref TR_7), but the timing update was explicitly requested by APE using cmtspeech_send_timing_request(). Note that library implementation may not necessarily be able to distinguish between TR_6 and TR_7, so both cases should be handled, and application must not rely on getting a TR_6 even if it issues cmtspeech_send_timing_request(). @subsection TR_7 CMTSPEECH_TR_7_TIMING_UPDATE Triggering protocol message is: CMTSPEECH_TIMING_CONFIG_NTF When new uplink timing parameters are sent by the modem, the protocol state doesn't change, but an event is still generated to relay the timing information to the client. See also @ref TR_6. @subsection TR_10 CMTSPEECH_TR_10_RESET Triggering protocol message is: CMTSPEECH_EVENT_RESET This event signals an error in protocol operation. Client can check the event message parameter 'cmt_sent_req' (::cmtspeech_event_t) to see whether it was CMT or APE that raised the error. @subsection TR_11 CMTSPEECH_TR_11_UL_STOP Triggering protocol message: CMTSPEECH_SPEECH_CONFIG_REQ This transition occurs when the speech channel parameters are changed during a call (e.g. due to a handover), and the uplink frame transmission should be stopped and reconfiguration is complete. The application should check the ... cmtevent.msg.speech_config_req.layout_changed ... field of the received event (::cmtspeech_event_t). If this is set to 'true', all uplink and downlink buffers currently held by the application have become invalid and should be released back to the library as soon as possible (using cmtspeech_dl_buffer_release() and cmtspeech_ul_buffer_release()). When the invalidated uplink buffers are released, no uplink frame is sent to the network. As all data traffic between APE and CMT is disabled until the buffers are released, application must act as quickly as possible. The current buffer contents are still accessible, so application can e.g. copy data out from the buffers, before releasing them back to the library. See also @ref TR_4. @subsection TR_12 CMTSPEECH_TR_12_UL_START Triggering protocol message is: CMTSPEECH_UPLINK_CONFIG_NTF With this event, cellular modem notifies APE that it has configured the DMA for uplink frame transfers, and that APE can start sending uplink frames. Once this event is received, application should start sending uplink speech frames with cmtspeech_ul_buffer_acquire() and cmtspeech_ul_buffer_release(). Modem may request APE to adjust the uplink timing at any time (see section @ref TR_6 and @ref TR_7). @section sect_passing_events Passing call signaling events to library The libcmtspeechdata library only handles data path communication towards the modem. There are however many dependencies between call control signaling and the data path setup, which the library client is responsible to handle. In Maemo5 (and Maemo6), client application can get the needed event information by subscribing to DBus events on the "com.nokia.csd.Call" interface. These messages are handled by Call Plugin (csd-call) to the Cellular Services Daemon (csd). Additionally application needs to listen for modem state changes events on the "com.nokia.phone.SSC" DBus interface. The following call signaling state changes need to be relayed to libcmtspeechdata: @subsection server_status 1. Change in call signaling server status When call signaling is started, or call signaling has terminated, client must pass the change state to the library with cmtspeech_state_change_call_status() API function. On Nokia modems, this state is the modem Call Server status (active or inactive). In Maemo5/6, this state is signaled by CSD using the 'com.nokia.csd.Call.ServerStatus' DBus interface. @subsection call_connected 2. Change in call connected status When call connection status changes (audio traffic channel is connected or disconnected), client must pass this state change to the library with cmtspeech_state_change_call_connect() API function. In Maemo5/6, there are two DBus signals emitted by CSD when connection status changes. The signals are 'com.nokia.csd.Call.Instance.AudioConnect' and 'com.nokia.csd.Call.UserConnection' signals (both signals are emitted). Again in Maemo5/6, it is currently recommended to listen to 'UserConnection(boolean)' and pass the paramater to libcmtspeechdata using the cmtspeech_state_change_call_connect() function. If 'AudioConnect' is used, the 'downlink' signal parameter should be passed on to cmtspeech_state_change_call_connect(). In addition to passing the information to the library, changes in call connection status may also impact application's own processing logic. E.g. when call is active, but not connected, the uplink frames are used only for timing. Thus the uplink frames provided to the library need not contain valid audio, and e.g. any additional CPU-intensive processing may be still disabled in this state. For example it is ok to send muted frames. The reason to keep sending uplink frames throughout calls is to maintain network timing. NOTE: Unlike uplink frames, which are sent all the time during a call, there can be gaps in the stream of downlink data frames. This can happen e.g. at start of the call before call is connected and during call hold. It is important that the application's playout mechanism can handle this case. @subsect modem_state_change 3. Modem state change Monitoring modem state changes is needed purely for handling exceptional error cases. In practise this means uncontrolled modem reboots (crashes and error states that cause a forced reboot). In Maemo5/6, the SSCD component (System State Controller Daemon) emits DBus signals for all modem state changes. The emitted signal is "com.nokia.phone.SSC.modem_state_changed_ind". If the state changes to "Initialize" while a libcmtspeechdata instance is not in disconnected state (cmtspeech_protocol_state() != CMTSPEECH_STATE_DISCONNECTED), application should consider the modem to have rebooted and close the library instance with cmtspeech_close(). The consequences of not closing the library instance in these error cases, are highly implementation specific. But for instance in Maemo5 devices, it is critical to correctly handle this scenario as keeping the libcmtspeechdata instance open even after the modem reboots, prevents from reestablishing the CMT-APE SSI connection, even if modem does succesfully boot back up. This is a fatal condition as the only way to recover is a reboot of the whole device. But with appropriate reaction to the modem reset, fast recovery is possible and no reboot is needed. @section sect_app_initiated_actions Actions initiated by application Once a call is established, the only libcmtspeechdata activity that needs to be triggered by the application (e.g. based on audio hardware interrupts, or using a system timer to wake up), is sending of uplink speech frames. The frames need to be sent according to the timing information provided by CMT. All other actions are triggered by either inbound events from the CMT, or by call signaling related DBus events. One optional action the application may take is to request for refreshed uplink timing. This can be accomplished by calling cmtspeech_send_timing_request().























*/ libcmtspeechdata-2.1.1+git20160721~8efc468/dummy-backend/000077500000000000000000000000001112705070200223325ustar00rootroot00000000000000libcmtspeechdata-2.1.1+git20160721~8efc468/dummy-backend/Makefile.am000066400000000000000000000022031112705070200243630ustar00rootroot00000000000000# Copyright (C) 2008,2009,2010 Nokia Corporation # Contact: Kai Vehmanen # Licensed under LGPL. See file COPYING. INCLUDES = -I${top_srcdir} -I$(top_builddir) lib_LTLIBRARIES = libcmtspeechdata.la libdir = ${exec_prefix}/lib/libcmtspeechdata-dummy # libcmtspeechdata main library sources # ------------------------------------- dummy_cmtspeechdata_pub_inc = \ cmtspeech_dummy.h \ dummy_common.h dummy_cmtspeechdata_common_src = \ ${top_srcdir}/cmtspeech_msgs.c \ ${top_srcdir}/cmtspeech_backend_common.c \ ${top_srcdir}/sal_debug.c #dummy_cmtspeechdata_pub_inc = \ # ${top_srcdir}/cmtspeech.h \ # ${top_srcdir}/cmtspeech_msgs.h dummy_cmtspeechdata_pub_inc_nodist = \ ${top_builddir}/cmtspeech_config.h libcmtspeechdata_la_SOURCES = \ $(dummy_cmtspeechdata_pub_inc) \ dummy_common.c \ cmtspeech_dummy.c nodist_libcmtspeechdata_la_SOURCES = \ $(dummy_cmtspeechdata_common_src) \ $(dummy_cmtspeechdata_pub_inc_nodist) libcmtspeechdata_la_CFLAGS = -prefer-pic libcmtspeechdata_la_LIBADD = -lrt libcmtspeechdata_la_LDFLAGS = \ -Wl,--version-script,$(top_srcdir)/libcmtspeechdata.ver \ -version-info 1:0:1 libcmtspeechdata-2.1.1+git20160721~8efc468/dummy-backend/cmtspeech_dummy.c000066400000000000000000000546101112705070200256720ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech_dummy.c * * Dummy user-space implementation of the CMT Speech Data * Backend interface. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "cmtspeech.h" #include "cmtspeech_msgs.h" #include "cmtspeech_backend_common.h" /* Build-time configuration */ /* -------------------------------------------------------------------- */ /* Select sampling rate to use */ /*#define USE_SAMPLE_RATE_16K 1*/ #define USE_SAMPLE_RATE_8K 1 /* Select active debugging traces */ #define BUILD_WITH_DEBUG 1 #define BUILD_WITH_DEBUG_TOKENS 1 #include "sal_debug.h" #define DEBUG_PREFIX "dummy_backend: " #include "cmtspeech_dummy.h" #include "dummy_common.h" #define SAL_BUFFER_SLOTS 5 #define SAL_MSG_BUFFER 256 #define SAL_TIMEOUT_LONG_MS 300000 /* 5min */ /* Definitions derived from build-time configuration */ /* -------------------------------------------------------------------- */ #if CMTSPEECH_BIG_ENDIAN_CMDS #define BYTE0 0 /* MSB byte */ #define BYTE1 1 #define BYTE2 2 #define BYTE3 3 /* LSB byte */ #elif CMTSPEECH_LITTLE_ENDIAN_CMDS #define BYTE0 3 /* MSB byte */ #define BYTE1 2 #define BYTE2 1 #define BYTE3 0 /* LSB byte */ #else #error "Endianess must be set." #endif #ifdef USE_SAMPLE_RATE_16K #define SAL_SAMPLE_RATE 16000 #define SAL_FRAME_SIZE_OCTETS 640 /* 20ms at mono/16kHz */ #elif USE_SAMPLE_RATE_8K #define SAL_SAMPLE_RATE 8000 #define SAL_FRAME_SIZE_OCTETS 320 /* 20ms at mono/8kHz */ #else #error "Sample rate not selected." #endif /* Data types */ /* -------------------------------------------------------------------- */ enum { STATE_IDLE = 0, /**< call server not active */ STATE_INITIALIZED, /**< call has been activated on CMT side */ STATE_MEDIA_FLOWING, /**< at least UL frames are being sent */ STATE_TERMINATING, /**< call termination has started */ }; enum { THREAD_NOT_STARTED = 0, THREAD_STARTED, THREAD_RUNNING, THREAD_EXIT_REQ, THREAD_TERMINATED }; struct dummy_state_s { volatile int state; volatile bool dl_active; volatile bool call_server_status; pthread_mutex_t writelock; }; struct cmtspeech_dummy_s { cmtspeech_bc_state_t bcstate; /**< protocol state */ struct dummy_state_s s; int ul_buf_idx; int dl_buf_idx; uint16_t dl_frame_counter; int control_pipes[2]; /**< pipe for delivering events to client */ int thread_pipes[2]; /**< pipe for delivering events to worker thread */ pthread_t worker; volatile int thread_running; uint8_t pubbuf[SAL_MSG_BUFFER]; /**< used in client context only */ int pubbuf_write; int pubbuf_read; dummy_buffer_t ul_buffers[SAL_BUFFER_SLOTS]; dummy_buffer_t dl_buffers[SAL_BUFFER_SLOTS]; dummy_tone_t *tone; dummy_poll_timer_t poll_timer; }; #define DUMMY_DL_DATA_AVAIL 0x01 #define DUMMY_UL_DATA_SENT 0x02 #define DUMMY_CMT_ALIVE 0x03 #define DUMMY_EXIT_REQUEST 0x04 /* Function definitions */ /* -------------------------------------------------------------------- */ /** * Encodes a dummy backend message 'type' to buffer pointed * by 'buf'. Returns size of encoded data (in octets). * * @param type is one of DUMMY_DL_DATA_AVAIL, DUMMY_UL_DATA_SENT, DUMMY_CMT_ALIVE */ static int cmtspeech_msg_encode_dummy_internal_message(uint8_t *buf, int len, uint8_t type) { if (len < 4) return -1; buf[BYTE0] = (type << 4) | CMTSPEECH_DOMAIN_INTERNAL; buf[BYTE1] = 0x0; buf[BYTE2] = 0x0; buf[BYTE3] = 0x0; return 4; } static int priv_change_state(cmtspeech_dummy_t *self, int new_state) { int res = -1; if (self->s.state != new_state) { res = pthread_mutex_lock(&self->s.writelock); self->s.state = new_state; pthread_mutex_unlock(&self->s.writelock); ONTRACE(printf(DEBUG_PREFIX "changed state to %d.\n", new_state)); } return res; } static int init_buffer_slot(dummy_buffer_t *slot, int index) { slot->buf.type = CMTSPEECH_BUFFER_TYPE_PCM_S16_LE; slot->buf.count = 4 + SAL_FRAME_SIZE_OCTETS; /* 32bit header plus 20ms of 16bit audio */; slot->buf.pcount = SAL_FRAME_SIZE_OCTETS; slot->buf.size = slot->buf.count; slot->buf.frame_flags = 0; slot->buf.spc_flags = 0; slot->buf.data = malloc(slot->buf.size); slot->buf.payload = slot->buf.data + 4; slot->buf.index = index; slot->locked = 0; if (!slot->buf.data) return -1; return 0; } static int free_buffer_slot(dummy_buffer_t *slot) { free(slot->buf.data); memset(slot, 0, sizeof(dummy_buffer_t)); return 0; } /** * Emits a SPEECH_CONFIG_REQ towards APE: */ static void priv_emit_speech_config_req(cmtspeech_dummy_t *priv, uint8_t speech_data, uint8_t user_connect) { cmtspeech_cmd_t msg; int res = cmtspeech_msg_encode_speech_config_req(&msg, speech_data, user_connect, CMTSPEECH_CODEC_INFO_GSM_HR, CMTSPEECH_CELLULAR_INFO_GSM, #if USE_SAMPLE_RATE_16K CMTSPEECH_SAMPLE_RATE_16KHZ, #elif USE_SAMPLE_RATE_8K CMTSPEECH_SAMPLE_RATE_8KHZ, #else #error "Sampling rate not set." #endif CMTSPEECH_DATA_FORMAT_S16LINPCM); assert(res > 0); res = write(priv->control_pipes[1], msg.d.buf, res); } /** * Processes messages sent to the internal message queue (APE->CMT * messages). * * The client will trigger processing when the handle (cmtspeech_descriptor()) * becomes readable. * * @see priv_read_control_message() */ static int handle_inbound_control_message(cmtspeech_dummy_t *priv, const cmtspeech_cmd_t msg) { int res = 0; uint8_t state = 0; uint8_t version = 0; int type = cmtspeech_msg_get_type(msg); int channel = cmtspeech_msg_get_domain(msg); cmtspeech_cmd_t tmpmsg; ONTRACE(printf(DEBUG_PREFIX "read APE->CMT message %s on channel %d.\n", cmtspeech_msg_type_to_string(msg), channel)); /* note: these are the APE->CMT messages */ if (channel == CMTSPEECH_DOMAIN_CONTROL) { switch(type) { case CMTSPEECH_SSI_CONFIG_REQ: /* step: parse received message */ cmtspeech_msg_decode_ssi_config_req(msg, NULL, &version, &state); res = cmtspeech_msg_encode_ssi_config_resp(&tmpmsg, CMTSPEECH_SAMPLE_LAYOUT_INORDER_LE, 0); assert(res > 0); write(priv->control_pipes[1], tmpmsg.d.buf, res); if (!state) priv_change_state(priv, STATE_IDLE); break; case CMTSPEECH_NEW_TIMING_CONFIG_REQ: if (priv->s.state == STATE_MEDIA_FLOWING) { res = cmtspeech_msg_encode_uplink_config_ntf(&tmpmsg); assert(res > 0); write(priv->control_pipes[1], tmpmsg.d.buf, res); } res = cmtspeech_msg_encode_timing_config_ntf(&tmpmsg, 5, 0); assert(res > 0); write(priv->control_pipes[1], tmpmsg.d.buf, res); break; case CMTSPEECH_SPEECH_CONFIG_RESP: break; case CMTSPEECH_SSI_CONFIG_RESP: case CMTSPEECH_SPEECH_CONFIG_REQ: case CMTSPEECH_TIMING_CONFIG_NTF: ONINFO(fprintf(stderr, DEBUG_PREFIX "ERROR: CMT->APE message received by CMT, type %d (%02X:%02X:%02X:%02x).\n", type, msg.d.buf[0], msg.d.buf[1], msg.d.buf[2], msg.d.buf[3])); res = -1; break; default: ONINFO(fprintf(stderr, DEBUG_PREFIX "ERROR: unknown control message of type %d (%02X:%02X:%02X:%02x).\n", type, msg.d.buf[0], msg.d.buf[1], msg.d.buf[2], msg.d.buf[3])); res = -1; } } else if (channel == CMTSPEECH_DOMAIN_INTERNAL) { int type = cmtspeech_msg_get_type(msg); if (type == DUMMY_EXIT_REQUEST) { ONINFO(printf(DEBUG_PREFIX "exit request received, exiting worked thread (running=%d)\n", priv->thread_running)); res = 0; } } else res = -1; return res; } /** * Reads and processes one pending control message sent * to the internal queue (APE->CMT messages). * * @see handle_inbound_control_message() */ static int priv_read_control_message(cmtspeech_dummy_t *priv, struct pollfd *fds) { cmtspeech_cmd_t msg; int i; ONDEBUG_TOKENS(fprintf(stderr, "E")); if (fds->revents & POLLIN) ONDEBUG(printf(DEBUG_PREFIX "thread wakeup - inbound control message\n")); /* note: SSI transfers are always at least 32bits (CMTSPEECH_CTRL_LEN) */ i = read(fds->fd, msg.d.buf, CMTSPEECH_CTRL_LEN); if (i == CMTSPEECH_CTRL_LEN) handle_inbound_control_message(priv, msg); return i; } /** * The main loop for the dummy backend. */ static void *worker_thread(void *context) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; struct pollfd fds; cmtspeech_cmd_t msg; if (priv->thread_running == THREAD_STARTED) priv->thread_running = THREAD_RUNNING; ONDEBUG(printf(DEBUG_PREFIX "ssi-audio-dummy thread started\n")); while(1) { int res; int timeout; int cur_state = priv->s.state; if (priv->thread_running >= THREAD_EXIT_REQ) break; switch (cur_state) { case STATE_IDLE: case STATE_INITIALIZED: case STATE_TERMINATING: /* step: wait for control messages (sleep time max 60000ms) */ fds.fd = priv->thread_pipes[0]; fds.events = POLLIN; timeout = SAL_TIMEOUT_LONG_MS; res = poll(&fds, 1, timeout); /* case: inbound control message */; if (res > 0) priv_read_control_message(priv, &fds); else if (res < 0) ONDEBUG(fprintf(stderr, DEBUG_PREFIX "Poll error %d (%d).\n", res, errno)); else ONTRACE(printf(DEBUG_PREFIX "dummy backend thread idle (state=%d, poll=%d)\n", cur_state, res)); break; case STATE_MEDIA_FLOWING: /* step: wake up at least every 20msec to generate DL frames */ fds.fd = priv->thread_pipes[0]; fds.events = POLLIN; /* step: adjust poll timeout based on actual time elapsed */ if (priv->s.dl_active == true) { timeout = dummy_poll_timer_pre_poll(&priv->poll_timer); } else timeout = 100; ONDEBUG_TOKENS(fprintf(stderr, "i")); res = poll(&fds, 1, timeout); ONDEBUG_TOKENS(fprintf(stderr, "o")); /* case: inbound control message */; if (res > 0) { ONDEBUG_TOKENS(fprintf(stderr, "C")); priv_read_control_message(priv, &fds); } /* case: error */ else if (res < 0) { ONDEBUG_TOKENS(fprintf(stderr, "E")); if (errno == EINTR) continue; else { fprintf(stderr, "ERROR: "DEBUG_PREFIX "error in cmtspeech_dummmy worker thread\n"); priv->thread_running = THREAD_EXIT_REQ; } } /* case: generate DL frame if enough time has passed */ if (priv->s.dl_active != true) { ONDEBUG_TOKENS(fprintf(stderr, "K1")); } else if (dummy_poll_timer_is_elapsed(&priv->poll_timer, 5000000) != true) { ONDEBUG_TOKENS(fprintf(stderr, "K2")); } else { if (priv->dl_buffers[priv->dl_buf_idx].locked) printf("WARNING: " DEBUG_PREFIX "buffer overrun in DL direction.\n"); ONDEBUG_TOKENS(fprintf(stderr, "T")); priv->dl_buf_idx = (priv->dl_buf_idx + 1) % SAL_BUFFER_SLOTS; dummy_tone_fill_buffer_slot(priv->tone, &priv->dl_buffers[priv->dl_buf_idx], priv->dl_frame_counter++); cmtspeech_msg_encode_dummy_internal_message(msg.d.buf, CMTSPEECH_CTRL_LEN, DUMMY_DL_DATA_AVAIL); res = write(priv->control_pipes[1], msg.d.buf, CMTSPEECH_CTRL_LEN); assert(res == CMTSPEECH_CTRL_LEN); assert(cmtspeech_msg_get_domain(msg) == 0); dummy_poll_timer_elapsed_fixed_period(&priv->poll_timer); } break; default: assert(0); } } ONDEBUG(printf(DEBUG_PREFIX "thread stopping\n")); priv->thread_running = THREAD_TERMINATED; return 0; } cmtspeech_t* cmtspeech_open(void) { cmtspeech_dummy_t *priv = malloc(sizeof(cmtspeech_dummy_t)); if (priv) { int i, j; for(i = 0; i < SAL_BUFFER_SLOTS; i++) { init_buffer_slot(&priv->ul_buffers[i], i); init_buffer_slot(&priv->dl_buffers[i], i); } cmtspeech_bc_open(&priv->bcstate); priv->s.state = STATE_IDLE; priv->s.call_server_status = false; pthread_mutex_init(&priv->s.writelock, NULL); priv->ul_buf_idx = 0; priv->dl_buf_idx = 0; priv->dl_frame_counter = 0; priv->pubbuf_write = 0; priv->pubbuf_read = 0; priv->tone = dummy_tone_initialize("sine"); dummy_poll_timer_init(&priv->poll_timer, 20); i = pipe(priv->control_pipes); j = pipe(priv->thread_pipes); if (i || j || priv->tone == NULL) { ONINFO(fprintf (stderr, DEBUG_PREFIX "ERROR: unable to allocate resources (pipes %d+%d, tone=%p)\n", i, j, priv->tone)); free(priv); priv = NULL; } else { int pthres; fcntl(priv->control_pipes[0], F_SETFD, O_NONBLOCK); fcntl(priv->thread_pipes[0], F_SETFD, O_NONBLOCK); priv->thread_running = THREAD_STARTED; pthres = pthread_create(&priv->worker, NULL, worker_thread, priv); assert(pthres == 0); } } return (cmtspeech_t*)priv; } int cmtspeech_close(cmtspeech_t *context) { int res = 0; if (context) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; int i, *thres = NULL; void *retval = thres; cmtspeech_cmd_t msg; if (priv->thread_running >= THREAD_STARTED) { priv->thread_running = THREAD_EXIT_REQ; } cmtspeech_msg_encode_dummy_internal_message(msg.d.buf, CMTSPEECH_CTRL_LEN, DUMMY_EXIT_REQUEST); res = write(priv->thread_pipes[1], msg.d.buf, CMTSPEECH_CTRL_LEN); assert(res == CMTSPEECH_CTRL_LEN); if (priv->thread_running >= THREAD_STARTED) { pthread_join(priv->worker, &retval); assert(priv->thread_running == THREAD_TERMINATED); } /* close sockets */ for(i = 0; i < SAL_BUFFER_SLOTS; i++) { free_buffer_slot(&priv->ul_buffers[i]); free_buffer_slot(&priv->dl_buffers[i]); } close(priv->control_pipes[0]); close(priv->control_pipes[1]); close(priv->thread_pipes[0]); close(priv->thread_pipes[1]); dummy_tone_release(priv->tone); free(priv); } else res = -1; return res; } int cmtspeech_descriptor(cmtspeech_t *context) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; return priv->control_pipes[0]; } int cmtspeech_check_pending(cmtspeech_t *context, int *flags) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; int res; if ((priv->pubbuf_write + CMTSPEECH_DATA_HEADER_LEN) % SAL_MSG_BUFFER == priv->pubbuf_read) { ONINFO(fprintf(stderr, DEBUG_PREFIX "ERROR: event queue overflow!\n")); if (flags) *flags = CMTSPEECH_EVENT_CONTROL; return 1; } res = read(priv->control_pipes[0], &priv->pubbuf[priv->pubbuf_write], CMTSPEECH_DATA_HEADER_LEN); if (flags) *flags = 0; if (res > 0) { cmtspeech_cmd_t msg; memcpy(msg.d.buf, &priv->pubbuf[priv->pubbuf_write], CMTSPEECH_CTRL_LEN); int channel = cmtspeech_msg_get_domain(msg); /* note: only queue control events (ignore data wakeups) */ if (channel == CMTSPEECH_DOMAIN_CONTROL) { priv->pubbuf_write += res; priv->pubbuf_write %= SAL_MSG_BUFFER; if (flags) *flags = CMTSPEECH_EVENT_CONTROL; } else if (channel == CMTSPEECH_DOMAIN_INTERNAL) { int type = cmtspeech_msg_get_type(msg); if (flags && type == DUMMY_DL_DATA_AVAIL) *flags = CMTSPEECH_EVENT_DL_DATA; } return 1; } return 0; } int cmtspeech_read_event(cmtspeech_t *context, cmtspeech_event_t *event) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; int res; cmtspeech_cmd_t msg; uint8_t *pubbuf = &priv->pubbuf[priv->pubbuf_read]; assert(event); memcpy (msg.d.buf, pubbuf, CMTSPEECH_CTRL_LEN); /* note: these are the CMT->APE messages */ res = cmtspeech_bc_handle_command(&priv->bcstate, context, msg, event); if (event->msg_type == CMTSPEECH_SSI_CONFIG_RESP) { /* step: enable DL */ if (priv->bcstate.proto_state == CMTSPEECH_STATE_CONNECTED) { ONTRACE(printf(DEBUG_PREFIX "Emitting SPEECH_CONFIG_REQ(enable)\n")); priv_emit_speech_config_req(priv, 1, 1); } } else if (event->msg_type == CMTSPEECH_SPEECH_CONFIG_REQ) { uint8_t reply_result = 0; cmtspeech_cmd_t respcmd; cmtspeech_msg_encode_speech_config_resp(&respcmd, reply_result); cmtspeech_bc_post_command(&priv->bcstate, context, respcmd); priv->s.dl_active = true; } cmtspeech_bc_complete_event_processing(&priv->bcstate, context, event); if (event->state == CMTSPEECH_STATE_CONNECTED && event->prev_state == CMTSPEECH_STATE_DISCONNECTED) { priv_change_state(priv, STATE_MEDIA_FLOWING); } ONDEBUG(printf(DEBUG_PREFIX "POP pubbuf r-old:%d, r-new:%d w:%d\n", priv->pubbuf_read, (priv->pubbuf_read + CMTSPEECH_CTRL_LEN) % SAL_MSG_BUFFER, priv->pubbuf_write)); priv->pubbuf_read += CMTSPEECH_CTRL_LEN; priv->pubbuf_read %= SAL_MSG_BUFFER; return res; } int cmtspeech_state_change_call_status(cmtspeech_t *context, bool status) { cmtspeech_dummy_t *self = (cmtspeech_dummy_t*)context; int res = cmtspeech_bc_state_change_call_status(context, status); ONTRACE(printf(DEBUG_PREFIX "ServerStatus - %d\n", status)); if (!status) { self->s.dl_active = false; } if (self->s.call_server_status != status) { self->s.call_server_status = status; if (status) { priv_change_state(self, STATE_INITIALIZED); } else { priv_change_state(self, STATE_TERMINATING); if (self->bcstate.proto_state == CMTSPEECH_STATE_ACTIVE_DL || self->bcstate.proto_state == CMTSPEECH_STATE_ACTIVE_DLUL) { ONTRACE(printf(DEBUG_PREFIX "Emitting SPEECH_CONFIG_REQ(disable)\n")); priv_emit_speech_config_req(self, 0, 0); } } } else ONTRACE(printf(DEBUG_PREFIX "No change, ignoring ServerStatus indication\n")); return res; } int cmtspeech_state_change_call_connect(cmtspeech_t *context, bool state) { cmtspeech_dummy_t *self = (cmtspeech_dummy_t*)context; ONTRACE(printf(DEBUG_PREFIX "AudioConnect state:%d\n", state)); self->s.dl_active = state; return cmtspeech_bc_state_change_call_connect(context, state); } int cmtspeech_state_change_error(cmtspeech_t *context) { /* XXX: not implemented */ return -1; } int cmtspeech_dl_buffer_acquire(cmtspeech_t *context, cmtspeech_buffer_t **buf) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; if (buf == NULL) return -EINVAL; SOFT_ASSERT(priv->dl_buffers[priv->dl_buf_idx].locked == 0); *buf = &priv->dl_buffers[priv->dl_buf_idx].buf; priv->dl_buffers[priv->dl_buf_idx].locked = 1; return 0; } int cmtspeech_dl_buffer_release(cmtspeech_t *context, cmtspeech_buffer_t *buf) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; int res = 0; if (!priv->dl_buffers[buf->index].locked) { ONINFO(fprintf(stderr, DEBUG_PREFIX "ERROR: trying to release an unlocked DL buffer.\n")); res = -ENOENT; } else if (&priv->dl_buffers[buf->index].buf != buf) { ONINFO(fprintf(stderr, DEBUG_PREFIX "ERROR: trying to release on invalid UL buffer.\n")); res = -EINVAL; } else { priv->dl_buffers[buf->index].locked = 0; /* XXX: process UL audio (write to file or loop back */ } return res; } cmtspeech_buffer_t *cmtspeech_dl_buffer_find_with_data(cmtspeech_t *context, uint8_t *data) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; int i; for(i = 0; i < SAL_BUFFER_SLOTS; i++) { if (priv->dl_buffers[i].buf.data == data) return &priv->dl_buffers[i].buf; } return NULL; } cmtspeech_buffer_t *cmtspeech_dl_buffer_find_with_payload(cmtspeech_t *context, uint8_t *payload) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; int i; for(i = 0; i < SAL_BUFFER_SLOTS; i++) { if (priv->dl_buffers[i].buf.payload == payload) return &priv->dl_buffers[i].buf; } return NULL; } int cmtspeech_test_data_ramp_req(cmtspeech_t *context, uint8_t rampstart, uint8_t ramplen) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; return cmtspeech_bc_test_data_ramp_req(&priv->bcstate, context, priv->thread_pipes[1], CMTSPEECH_DOMAIN_CONTROL, CMTSPEECH_DOMAIN_DATA, rampstart, ramplen); } int cmtspeech_send_timing_request(cmtspeech_t *context) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; return cmtspeech_bc_send_timing_request(&priv->bcstate, context, priv->thread_pipes[1]); } int cmtspeech_send_ssi_config_request(cmtspeech_t *context, bool state) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; return cmtspeech_bc_send_ssi_config_request(&priv->bcstate, context, priv->thread_pipes[1], state); } int cmtspeech_ul_buffer_acquire(cmtspeech_t *context, cmtspeech_buffer_t **buf) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; if (buf == NULL) return -EINVAL; *buf = &priv->ul_buffers[priv->ul_buf_idx].buf; priv->ul_buffers[priv->ul_buf_idx].locked = 1; ++priv->ul_buf_idx; if (priv->ul_buf_idx == SAL_BUFFER_SLOTS) priv->ul_buf_idx = 0; return 0; } int cmtspeech_ul_buffer_release(cmtspeech_t *context, cmtspeech_buffer_t *buf) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; int res = 0; if (!priv->ul_buffers[buf->index].locked) { ONINFO(fprintf(stderr, DEBUG_PREFIX "ERROR: trying to release an unlocked UL buffer.\n")); res = -EINVAL; } else if (&priv->ul_buffers[buf->index].buf != buf) { ONINFO(fprintf(stderr, DEBUG_PREFIX "ERROR: trying to release on invalid UL buffer.\n")); res = -EINVAL; } else { priv->ul_buffers[buf->index].locked = 0; /* XXX: store the sent UL buffer for verification */ } return res; } const char* cmtspeech_backend_name(cmtspeech_t* context) { return CMTSPEECH_DUMMY_BACKEND_ID; } int cmtspeech_backend_message(cmtspeech_t *self, int type, int args, ...) { return -1; } int cmtspeech_buffer_codec_sample_rate(cmtspeech_buffer_t *context) { return CMTSPEECH_SAMPLE_RATE_NONE; } int cmtspeech_buffer_sample_rate(cmtspeech_buffer_t *context) { return CMTSPEECH_SAMPLE_RATE_NONE; } cmtspeech_bc_state_t *cmtspeech_bc_state_object(cmtspeech_t *context) { cmtspeech_dummy_t *priv = (cmtspeech_dummy_t*)context; return &priv->bcstate; } libcmtspeechdata-2.1.1+git20160721~8efc468/dummy-backend/cmtspeech_dummy.h000066400000000000000000000027731112705070200257020ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech_dummy.h * * Dummy user-space implementation of the CMT Speech Data * Backend interface. */ #ifndef INCLUDED_CMTSPEECH_DUMMY_H #define INCLUDED_CMTSPEECH_DUMMY_H #include #define CMTSPEECH_DUMMY_BACKEND_ID "cmtspeech_dummy" /** * General list of TODO items: * * - separate public dummy control interface from the * internal context struct (to have a better interface * for simple_csmediad and others) */ struct cmtspeech_dummy_s; typedef struct cmtspeech_dummy_s cmtspeech_dummy_t; #define CMTSPEECH_DUMMY_EVENT_AUDIO_CONNECT 0 #define CMTSPEECH_DUMMY_EVENT_SERVER_STATUS 1 #endif libcmtspeechdata-2.1.1+git20160721~8efc468/dummy-backend/dummy_common.c000066400000000000000000000165301112705070200252060ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file dummy_common.c * * Common functions for CMT emulation code. */ #include #include #include #include #include #include #include #include "cmtspeech_msgs.h" #include "dummy_common.h" #include "sal_debug.h" #define DEBUG_PREFIX "dummy_common: " /* #define BIG_ENDIAN_SAMPLES 1 */ #define LITTLE_ENDIAN_SAMPLES 1 /** * Returns result of 'a - b'. Only accurate when the difference * within one second. */ static long rough_diff_ns(struct timespec *a, struct timespec *b) { if (a->tv_sec == b->tv_sec) return a->tv_nsec - b->tv_nsec; else if (a->tv_sec == b->tv_sec + 1 && a->tv_nsec - b->tv_nsec < 0) return 999999999 + a->tv_nsec - b->tv_nsec; else if (a->tv_sec > b->tv_sec) return 999999999; else return -999999999; } int dummy_tone_fill_buffer(dummy_tone_t *tone, uint8_t *buf, int bufsize) { int i; /* note: i is index to 16bit frames in the buffer */ for(i = 0; i < bufsize / 2; i++) { /* reverse byte order if needed (array LE) */ int16_t value = #if BIG_ENDIAN_SAMPLES htons(tone->tone_buf[tone->tone_pos]) #else tone->tone_buf[tone->tone_pos] #endif ; memcpy(&buf[i * 2], &value, sizeof(value)); tone->tone_pos = (tone->tone_pos + 1) % (tone->tone_len / 2); } return 0; } int dummy_tone_fill_buffer_slot(dummy_tone_t *tone, dummy_buffer_t *slot, uint16_t counter) { int i = 0, j; j = cmtspeech_msg_encode_dl_data_header(slot->buf.data, CMTSPEECH_DATA_HEADER_LEN, counter, CMTSPEECH_SPC_FLAGS_SPEECH, CMTSPEECH_DATA_LENGTH_20MS, CMTSPEECH_SAMPLE_RATE_16KHZ, CMTSPEECH_DATA_TYPE_VALID); assert(j == CMTSPEECH_DATA_HEADER_LEN); /* note: i is index to 16bit frames in the buffer */ for(i = 2; i < slot->buf.size / 2; i++) { /* reverse byte order if needed (array LE) */ int16_t value = #if BIG_ENDIAN_SAMPLES htons(tone->tone_buf[tone->tone_pos]) #else tone->tone_buf[tone->tone_pos] #endif ; memcpy(&slot->buf.data[i * 2], &value, sizeof(value)); tone->tone_pos = (tone->tone_pos + 1) % (tone->tone_len / 2); } slot->buf.count = slot->buf.size; slot->buf.pcount = slot->buf.size - CMTSPEECH_DATA_HEADER_LEN; return 0; } dummy_tone_t *dummy_tone_initialize(const char *typestr) { int len; dummy_tone_t *tone = NULL; char *getenv_dummysrc = getenv("DUMMYSRC"); const char *dummysrc = NULL; if (getenv_dummysrc) dummysrc = getenv_dummysrc; if (!dummysrc) dummysrc = typestr; if (!dummysrc) return tone; if (strcmp(dummysrc, "sine") == 0) { /* * 400 Hz sin wave as signed 16-bit array */ static const int16_t sinwave[20] = { 0, 2531, 4814, 6626, 7790, 8191, 7790, 6626, 4814, 2531, 0, -2531, -4814, -6626, -7790, -8191, -7790, -6626, -4814, -2531 }; tone = malloc(sizeof(*tone)); tone->tone_len = sizeof(int16_t) * 20; tone->tone_buf = malloc(tone->tone_len); tone->tone_pos = 0; if (tone->tone_buf) { memcpy(tone->tone_buf, sinwave, tone->tone_len); ONTRACE(printf(DEBUG_PREFIX "tone buf created of length %d, sine tone\n", tone->tone_len)); } else { free(tone); tone = NULL; } } else { FILE *f = fopen(dummysrc, "rw"); int res; if (f) { res = fseek(f, 0, SEEK_END); len = ftell(f); res = fseek(f, 0, SEEK_SET); if (res == 0 && len > 0) { ssize_t read_bytes; tone = malloc(sizeof(*tone)); tone->tone_len = len; tone->tone_buf = malloc(len); tone->tone_pos = 0; if (tone->tone_buf) { read_bytes = fread(tone->tone_buf, 1, tone->tone_len, f); if (len != read_bytes) { free(tone); tone = NULL; } else { ONTRACE(printf(DEBUG_PREFIX "tone buf created of length %d, file %s, len %d, res %d.\n", tone->tone_len, dummysrc, len, res)); } } else { free(tone); tone = NULL; } } fclose(f); } else { ONINFO(printf(DEBUG_PREFIX "unable to open tone file %s\n", dummysrc)); free(tone); tone = NULL; } } return tone; } void dummy_tone_release(dummy_tone_t *tone) { free(tone->tone_buf); tone->tone_buf = NULL; tone->tone_len = 0; tone->tone_pos = 0; free(tone); } void dummy_poll_timer_init(dummy_poll_timer_t *self, int period_ms) { self->has_elapsed = 0; self->baseperiod_ns = period_ms * 1000000L; memset(&self->last_elapsed, 0, sizeof(self->last_elapsed)); } /** * Calculates poll time out for timer 'self'. * * @return timeout in milliseconds */ int dummy_poll_timer_pre_poll(dummy_poll_timer_t *self) { int timeout; clock_gettime(CLOCK_MONOTONIC, &self->prepoll); if (self->has_elapsed == 1) { long cycle = rough_diff_ns(&self->prepoll, &self->last_elapsed); if (cycle >= self->baseperiod_ns) timeout = 0; else timeout = (self->baseperiod_ns - cycle) / 1000000L + 1; } else timeout = self->baseperiod_ns / 1000000L; /* fprintf(stderr, "pre_poll timeout %d\n", timeout); */ return timeout; } /** * Checks whether event deadline has been reached. * * @see dummy_poll_timer_event_sent() * @see dummy_poll_timer_event_sent_fixed_period() * * @return true or false */ bool dummy_poll_timer_is_elapsed(dummy_poll_timer_t *self, long margin_ns) { struct timespec now; long cycle; clock_gettime(CLOCK_MONOTONIC, &now); cycle = rough_diff_ns(&now, &self->last_elapsed); /* fprintf(stderr, "cycle %lu, res %d\n", cycle, cycle >= self->baseperiod_ns); */ if (cycle + margin_ns >= self->baseperiod_ns) return true; return false; } /** * Sets the time, when timer last elapsed, to current system time. * This is used to calculate when the timer should fire next. * * @see dummy_oll_timer_is_elapsed() * @see dummy_poll_timer_event_sent_fixed_period() */ void dummy_poll_timer_elapsed(dummy_poll_timer_t *self) { clock_gettime(CLOCK_MONOTONIC, &self->last_elapsed); if (self->has_elapsed == 0) self->has_elapsed = 1; } /** * Sets the time, when timer last elapsed, by adding * timer base period to previous recorded timer * timestamp. * * @see dummy_oll_timer_is_elapsed() * @see dummy_poll_timer_event_sent() */ void dummy_poll_timer_elapsed_fixed_period(dummy_poll_timer_t *self) { if (self->has_elapsed == 0) { self->has_elapsed = 1; clock_gettime(CLOCK_MONOTONIC, &self->last_elapsed); } else { self->last_elapsed.tv_nsec += self->baseperiod_ns; if (self->last_elapsed.tv_nsec > 999999999) { ++self->last_elapsed.tv_sec; self->last_elapsed.tv_nsec -= 1000000000; } } } libcmtspeechdata-2.1.1+git20160721~8efc468/dummy-backend/dummy_common.h000066400000000000000000000042721112705070200252130ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file dummy_common.h * * Common functions for CMT emulation code. */ #ifndef INCLUDED_DUMMY_COMMON_H #define INCLUDED_DUMMY_COMMON_H #include #include #include "cmtspeech.h" struct dummy_buffer_s { cmtspeech_buffer_t buf; int locked; }; typedef struct dummy_buffer_s dummy_buffer_t; struct dummy_tone_s { int16_t *tone_buf; int tone_len; int tone_pos; }; typedef struct dummy_tone_s dummy_tone_t; struct dummy_poll_timer_s { int has_elapsed; struct timespec prepoll; struct timespec last_elapsed; long baseperiod_ns; }; typedef struct dummy_poll_timer_s dummy_poll_timer_t; int dummy_tone_fill_buffer(dummy_tone_t *tone, uint8_t *buf, int bufsize); int dummy_tone_fill_buffer_slot(dummy_tone_t *tone, dummy_buffer_t *slot, uint16_t counter); dummy_tone_t *dummy_tone_initialize(const char *typestr); void dummy_tone_release(dummy_tone_t *tone); void dummy_poll_timer_init(dummy_poll_timer_t *self, int period_ms); int dummy_poll_timer_pre_poll(dummy_poll_timer_t *self); void dummy_poll_timer_elapsed(dummy_poll_timer_t *self); void dummy_poll_timer_elapsed_fixed_period(dummy_poll_timer_t *self); bool dummy_poll_timer_is_elapsed(dummy_poll_timer_t *self, long margin_ns); int dummy_tone_calc_timeout(int base_cycle_ms, struct timespec *prev); #endif /* INCLUDED_DUMMY_COMMON_H */ libcmtspeechdata-2.1.1+git20160721~8efc468/kernel-headers/000077500000000000000000000000001112705070200225035ustar00rootroot00000000000000libcmtspeechdata-2.1.1+git20160721~8efc468/kernel-headers/linux/000077500000000000000000000000001112705070200236425ustar00rootroot00000000000000libcmtspeechdata-2.1.1+git20160721~8efc468/kernel-headers/linux/cs-protocol.h000066400000000000000000000073571112705070200262730ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /* * @file include/linux/cs-protocol.h - cmt_speech interface definitions * * Implemented by: * - drivers/misc/cmt-speech/ * * Copyright (C) 2008,2009,2010 Nokia Corporation. All rights reserved. * * Contact: Kai Vehmanen * Original author: Peter Ujfalusi */ #ifndef _CS_PROTOCOL_H #define _CS_PROTOCOL_H #include #include /* chardev parameters */ #define CS_DEV_FILE_NAME "/dev/cmt_speech" /* user-space API versioning */ #define CS_IF_VERSION 2 /* APE kernel <-> user space messages */ #define CS_CMD_SHIFT 28 #define CS_DOMAIN_SHIFT 24 #define CS_CMD_MASK 0xff000000 #define CS_PARAM_MASK 0xffffff #define CS_CMD(id, dom) \ (((id) << CS_CMD_SHIFT) | ((dom) << CS_DOMAIN_SHIFT)) #define CS_ERROR CS_CMD(1, 0) #define CS_RX_DATA_RECEIVED CS_CMD(2, 0) #define CS_TX_DATA_READY CS_CMD(3, 0) #define CS_TX_DATA_SENT CS_CMD(4, 0) /* params to CS_ERROR indication */ #define CS_ERR_PEER_RESET 0 /* ioctl interface */ /* parameters to CS_CONFIG_BUFS ioctl */ #define CS_FEAT_TSTAMP_RX_CTRL (1 << 0) #define CS_FEAT_ROLLING_RX_COUNTER (2 << 0) /* parameters to CS_GET_STATE ioctl */ #define CS_STATE_CLOSED 0 #define CS_STATE_OPENED 1 /* resource allocated */ #define CS_STATE_CONFIGURED 2 /* data path active */ /* maximum number of TX/RX buffers */ #define CS_MAX_BUFFERS_SHIFT 4 #define CS_MAX_BUFFERS (1 << CS_MAX_BUFFERS_SHIFT) /* Parameters for setting up the data buffers */ struct cs_buffer_config { __u32 rx_bufs; /* number of RX buffer slots */ __u32 tx_bufs; /* number of TX buffer slots */ __u32 buf_size; /* bytes */ __u32 flags; /* see CS_FEAT_* */ __u32 reserved[4]; }; /* * Struct describing the layout and contents of the driver mmap area. * This information is meant as read-only information for the application. */ struct cs_mmap_config_block { __u32 reserved1; __u32 buf_size; /* 0=disabled, otherwise the transfer size */ __u32 rx_bufs; /* # of RX buffers */ __u32 tx_bufs; /* # of TX buffers */ __u32 reserved2; /* array of offsets within the mmap area for each RX and TX buffer */ __u32 rx_offsets[CS_MAX_BUFFERS]; __u32 tx_offsets[CS_MAX_BUFFERS]; __u32 rx_ptr; __u32 rx_ptr_boundary; __u32 reserved3[2]; /* * if enabled with CS_FEAT_TSTAMP_RX_CTRL, monotonic * timestamp taken when the last control command was received */ struct timespec tstamp_rx_ctrl; }; #define CS_IO_MAGIC 'C' #define CS_IOW(num, dtype) _IOW(CS_IO_MAGIC, num, dtype) #define CS_IOR(num, dtype) _IOR(CS_IO_MAGIC, num, dtype) #define CS_IOWR(num, dtype) _IOWR(CS_IO_MAGIC, num, dtype) #define CS_IO(num) _IO(CS_IO_MAGIC, num) #define CS_GET_STATE CS_IOR(21, unsigned int) #define CS_SET_WAKELINE CS_IOW(23, unsigned int) #define CS_GET_IF_VERSION CS_IOR(30, unsigned int) #define CS_CONFIG_BUFS CS_IOW(31, struct cs_buffer_config) #endif /* _CS_PROTOCOL_H */ libcmtspeechdata-2.1.1+git20160721~8efc468/libcmtspeechdata.pc.in000066400000000000000000000003471112705070200240430ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ libdir=@libdir@ Name: libcmtspeechdata Description: Cellular modem speech data library Version: @VERSION@ Cflags: -I${includedir} Libs: -L${libdir} -lcmtspeechdata libcmtspeechdata-2.1.1+git20160721~8efc468/libcmtspeechdata.ver000066400000000000000000000016741112705070200236340ustar00rootroot00000000000000{ global: cmtspeech_backend_message; cmtspeech_backend_name; cmtspeech_buffer_codec_sample_rate; cmtspeech_buffer_sample_rate; cmtspeech_check_pending; cmtspeech_close; cmtspeech_descriptor; cmtspeech_dl_buffer_acquire; cmtspeech_dl_buffer_find_with_data; cmtspeech_dl_buffer_find_with_payload; cmtspeech_dl_buffer_release; cmtspeech_event_to_state_transition; cmtspeech_init; cmtspeech_is_active; cmtspeech_is_ssi_connection_enabled; cmtspeech_open; cmtspeech_protocol_state; cmtspeech_protocol_version; cmtspeech_read_event; cmtspeech_send_ssi_config_request; cmtspeech_send_timing_request; cmtspeech_set_trace_handler; cmtspeech_set_wb_preference; cmtspeech_state_change_call_connect; cmtspeech_state_change_call_status; cmtspeech_state_change_error; cmtspeech_test_data_ramp_req; cmtspeech_trace_toggle; cmtspeech_ul_buffer_acquire; cmtspeech_ul_buffer_release; cmtspeech_version_str; cmtspeech_msg_*; local: *; }; libcmtspeechdata-2.1.1+git20160721~8efc468/mkit000077500000000000000000000017021112705070200205040ustar00rootroot00000000000000build_lib () { for a in test_cmtspeech test_cmtspeech_msgs test_ring; do echo $a # gcc cmtspeech_backend_common.c cmtspeech_msgs.c cmtspeech_nokiamodem.c sal_debug.c $a.c -I. -lrt -o $a done for a in cmtspeech_backend_common cmtspeech_msgs cmtspeech_nokiamodem sal_debug; do gcc -fPIC $a.c -c -I. -o $a.o done ar rcs libcmtspeech.a cmtspeech_backend_common.o cmtspeech_msgs.o cmtspeech_nokiamodem.o sal_debug.o } # http://www.freedesktop.org/software/pulseaudio/doxygen/structpa__buffer__attr.html # build_lib gcc -I . -I /usr/include/dbus-1.0/ -I /usr/lib/arm-linux-gnueabi/dbus-1.0/include/ utils/cmtspeech_ofono_test.c -lpthread -lrt libcmtspeech.a /usr/lib/arm-linux-gnueabi/libdbus-1.a $(pkg-config --cflags --libs libpulse-simple) -o cmtspeech_ofono_test gcc $(pkg-config --cflags --libs libpulse-simple) pa_test.c -o pa_test # git remote add gitorious git@gitorious.org:libcmtspeechdata/libcmtspeechdata.git # git push -u gitorious masterlibcmtspeechdata-2.1.1+git20160721~8efc468/pa_test.c000066400000000000000000000102061112705070200214140ustar00rootroot00000000000000/*** This file is part of PulseAudio. PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. PulseAudio is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with PulseAudio; if not, see . ***/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #define BUFSIZE 1024 int main(int argc, char*argv[]) { /* The sample type to use */ static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 4000, /* Requesting 8000 crashes pulseaudio */ .channels = 1 }; static const pa_buffer_attr attr = { .fragsize = (uint32_t) 1024, .maxlength = (uint32_t) -1, .minreq = (uint32_t) 1024, .prebuf = (uint32_t) -1, .tlength = (uint32_t) 1024, /* fragsize / tlength can be 4096 -> pulseaudio CPU drops from 33% CPU to 10%, but latency can be heard */ }; pa_simple *r = NULL; pa_simple *p = NULL; int ret = 1; int error; const pa_buffer_attr *p_attr = &attr; int opt = 0; // | PA_STREAM_ADJUST_LATENCY /* Create a new playback stream */ if (!(p = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK | opt, NULL, "playback", &ss, NULL, p_attr, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } /* Create the recording stream */ if (!(r = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD | opt, NULL, "record", &ss, NULL, p_attr, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } for (;;) { uint8_t buf[BUFSIZE]; /* Record some data ... */ if (pa_simple_read(r, buf, sizeof(buf), &error) < 0) { fprintf(stderr, __FILE__": pa_simple_read() failed: %s\n", pa_strerror(error)); goto finish; } /* ... and play it */ if (pa_simple_write(p, buf, sizeof(buf), &error) < 0) { fprintf(stderr, __FILE__": pa_simple_write() failed: %s\n", pa_strerror(error)); goto finish; } { pa_usec_t latency_p, latency_r; static pa_usec_t latency_p_avg, latency_r_avg; static int every; if ((latency_p = pa_simple_get_latency(p, &error)) == (pa_usec_t) -1) { fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error)); goto finish; } if ((latency_r = pa_simple_get_latency(r, &error)) == (pa_usec_t) -1) { fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error)); goto finish; } latency_p /= 1000.; latency_r /= 1000.; float factor = 0.01; latency_p_avg = (latency_p_avg * (1 - factor)) + latency_p * factor; latency_r_avg = (latency_r_avg * (1 - factor)) + latency_r * factor; every++; if (every == 1000) { fprintf(stderr, "\rplayback %7.2f msec avg %6.1f, record %7.2f msec avg %6.1f ", (float)latency_p, (float)latency_p_avg, (float)latency_r, (float)latency_r_avg); every = 0; } if (latency_r > 3330000) { fprintf(stderr, "...flush\n"); #if 0 if (pa_simple_flush(r, &error) < 0) { fprintf(stderr, __FILE__": pa_simple_flush() failed: %s\n", pa_strerror(error)); goto finish; } #endif } } } /* Make sure that every single sample was played */ if (pa_simple_drain(p, &error) < 0) { fprintf(stderr, __FILE__": pa_simple_drain() failed: %s\n", pa_strerror(error)); goto finish; } ret = 0; finish: if (r) pa_simple_free(r); if (p) pa_simple_free(p); return ret; } libcmtspeechdata-2.1.1+git20160721~8efc468/run000077500000000000000000000002561112705070200203470ustar00rootroot00000000000000#!/bin/bash echo "libcmtspeech data: preparing" sleep 50 echo "starting" cd /my/libcmtspeechdata nice -n -20 ./cmtspeech_ofono_test -a -v -v | tee /my/cmtspeech.log sleep 1h libcmtspeechdata-2.1.1+git20160721~8efc468/run2000077500000000000000000000000771112705070200204320ustar00rootroot00000000000000#!/bin/bash cd /my/libcmtspeechdata sudo nice -n -11 ./pa_test libcmtspeechdata-2.1.1+git20160721~8efc468/sal_debug.c000066400000000000000000000064501112705070200217100ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file sal_debug.c * * Debugging and tracing macros for libcmtspeechdata * internal usage. * * Acronym SAL refers to the old name of the library * (SSI audio library). */ #include #include #include #include #include "sal_debug.h" #include "cmtspeech.h" /* set default values */ int cmtspeech_trace_mask = TRACE_BIT_ERROR | TRACE_BIT_INFO; cmtspeech_trace_handler_t cmtspeech_glob_trace_f = NULL; int cmtspeech_initialize_tracing(void) { const char *debstr = getenv("CMTSPEECHDEBUG"); if (debstr) { if (strstr(debstr, "noinfo") != NULL) cmtspeech_trace_mask &= ~TRACE_BIT_INFO; else if (strstr(debstr, "info") != NULL) cmtspeech_trace_mask |= TRACE_BIT_INFO; #if !defined(NDEBUG) if (strstr(debstr, "notrace") != NULL) { cmtspeech_trace_mask &= ~TRACE_BIT_STATE_CHANGE; cmtspeech_trace_mask &= ~TRACE_BIT_IO; } else if (strstr(debstr, "trace") != NULL) { cmtspeech_trace_mask |= TRACE_BIT_STATE_CHANGE; cmtspeech_trace_mask |= TRACE_BIT_IO; } if (strstr(debstr, "nodebug") != NULL) cmtspeech_trace_mask &= ~TRACE_BIT_DEBUG; else if (strstr(debstr, "debug") != NULL) cmtspeech_trace_mask |= TRACE_BIT_DEBUG; if (strstr(debstr, "notoken") != NULL) cmtspeech_trace_mask &= ~TRACE_BIT_TOKEN; else if (strstr(debstr, "token") != NULL) cmtspeech_trace_mask |= TRACE_BIT_TOKEN; #endif /* !defined(NDEBUG) */ } return 0; } int cmtspeech_soft_assert(int v, const char* v_str, int line, const char *file) { #if !defined(NDEBUG) if (!v) { cmtspeech_trace_message(CMTSPEECH_TRACE_INFO, "ASSERT FAILED: %s:%d '%s'", file, line, v_str); } #endif return v; } void cmtspeech_trace_message(int priority, const char *message, ...) { va_list args; if (!((1 << priority) & cmtspeech_trace_mask)) return; va_start(args, message); if (cmtspeech_glob_trace_f != NULL) { cmtspeech_glob_trace_f(priority, message, args); } else { if (priority == CMTSPEECH_TRACE_ERROR) printf("ERROR: "); printf("CMTSPEECH: "); vprintf(message, args); printf("\n"); } va_end(args); } void cmtspeech_trace_toggle(int priority, bool enabled) { if (enabled == true) cmtspeech_trace_mask |= 1 << priority; else cmtspeech_trace_mask &= ~(1 << priority); } int cmtspeech_set_trace_handler(cmtspeech_trace_handler_t func) { cmtspeech_glob_trace_f = func; return 1; } libcmtspeechdata-2.1.1+git20160721~8efc468/sal_debug.h000066400000000000000000000075121112705070200217150ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file sal_debug.h * * Debugging and tracing macros for libcmtspeechdata * internal usage. Applications using libcmtspeechdata * should NOT include this file. * * Acronym SAL refers to the old name of the library * (SSI audio library). */ #ifndef INCLUDED_SAL_DEBUG_H #define INCLUDED_SAL_DEBUG_H #include "cmtspeech.h" /* Define which traces are compiled in */ #ifndef BUILD_WITH_INFO # define BUILD_WITH_INFO 1 #endif #ifndef BUILD_WITH_TRACE # define BUILD_WITH_TRACE 1 #endif #ifndef BUILD_WITH_DEBUG # define BUILD_WITH_DEBUG 0 #endif #ifndef BUILD_WITH_DEBUG_RING # define BUILD_WITH_DEBUG_RING 0 #endif #ifndef BUILD_WITH_DEBUG_TOKENS # define BUILD_WITH_DEBUG_TOKENS 0 #endif /* note: trace bits derived from public tracing levels */ #define TRACE_BIT_ERROR (1 << CMTSPEECH_TRACE_ERROR) #define TRACE_BIT_INFO (1 << CMTSPEECH_TRACE_INFO) #define TRACE_BIT_STATE_CHANGE (1 << CMTSPEECH_TRACE_STATE_CHANGE) #define TRACE_BIT_IO (1 << CMTSPEECH_TRACE_IO) #define TRACE_BIT_DEBUG (1 << CMTSPEECH_TRACE_DEBUG) /* note: trace bits that are implementation internal */ #define INTERNAL_TRACE_TOKEN CMTSPEECH_TRACE_INTERNAL #define TRACE_BIT_TOKEN (1 << INTERNAL_TRACE_TOKEN) extern int cmtspeech_trace_mask; /* Traces used by test applications */ /* ---------------------------------*/ #define TRACE_ERROR(x, ...) cmtspeech_trace_message(CMTSPEECH_TRACE_ERROR, x, ##__VA_ARGS__) #if BUILD_WITH_INFO #define ONINFO(x) do { if (cmtspeech_trace_mask & TRACE_BIT_INFO) { x; } } while(0) #define TRACE_INFO(x, ...) cmtspeech_trace_message(CMTSPEECH_TRACE_INFO, x, ##__VA_ARGS__) #else #define ONINFO(x) #define TRACE_INFO(x, ...) #endif #if BUILD_WITH_TRACE && !defined(NDEBUG) #define ONTRACE(x) do { if (cmtspeech_trace_mask & (TRACE_BIT_STATE_CHANGE|CMTSPEECH_TRACE_IO)) { x; } } while(0) #define TRACE_STATE_CHANGE(x, ...) cmtspeech_trace_message(CMTSPEECH_TRACE_STATE_CHANGE, x, ##__VA_ARGS__) #define TRACE_IO(x, ...) cmtspeech_trace_message(CMTSPEECH_TRACE_IO, x, ##__VA_ARGS__) #else #define ONTRACE(x) #define TRACE_STATE_CHANGE(x, ...) #define TRACE_IO(x, ...) #endif #if BUILD_WITH_DEBUG && !defined(NDEBUG) #define ONDEBUG(x) do { if (cmtspeech_trace_mask & TRACE_BIT_DEBUG) { x; } } while(0) #define TRACE_DEBUG(x, ...) cmtspeech_trace_message(CMTSPEECH_TRACE_DEBUG, x, ##__VA_ARGS__) #else #define ONDEBUG(x) #define TRACE_DEBUG(x, ...) #endif #if BUILD_WITH_DEBUG_TOKENS #define ONDEBUG_TOKENS(x) do { if (cmtspeech_trace_mask & TRACE_BIT_TOKEN) { x; } } while(0) #else #define ONDEBUG_TOKENS(x) #endif #if !defined(NDEBUG) #define SOFT_ASSERT(v) cmtspeech_soft_assert(v, #v, __LINE__, __FILE__) #else #define SOFT_ASSERT(v) #endif void cmtspeech_trace_message(int priority, const char *message, ...); void cmtspeech_trace_toggle(int priority, bool enabled); int cmtspeech_initialize_tracing(void); int cmtspeech_soft_assert(int v, const char* v_str, int line, const char *file); #endif /* INCLUDED_SAL_DEBUG_H */ libcmtspeechdata-2.1.1+git20160721~8efc468/sal_ring.h000066400000000000000000000072721112705070200215710ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file sal_ring.h * * Ring buffer implementation for libcmtspeechdata. * * The implementation is a simplified ring buffer with * no fill count tracking, but instead one octet is kept * open in the buffer (maximum fill is thus 'ring->size - 1'). * * Ring buffer size is not limited to power of two sizes. */ #ifndef INCLUDED_SAL_RING_H #define INCLUDED_SAL_RING_H #include struct ring_buffer_s { int read_idx; int write_idx; int size; /**< octets of allocated space */ uint8_t *data; /**< pointer to a buffer of 'size' octets */ }; typedef struct ring_buffer_s ring_buffer_t; /** * Initializes the ring buffer for use. * * @param ring self * @param buf pointer to buffer data area * @param size size of the data area in octets */ static inline void ring_buffer_init(ring_buffer_t *ring, uint8_t *buf, int size) { ring->read_idx = 0; ring->write_idx = 0; ring->size = size; ring->data = buf; } /** * Resets the ring buffer state. * * @param ring self */ static inline void ring_buffer_reset(ring_buffer_t *ring) { ring->read_idx = 0; ring->write_idx = 0; } /** * Returns number of octets that can be read (between 0 and * ring->size-1). */ static inline int ring_buffer_avail_for_read(ring_buffer_t *ring) { return (ring->write_idx - ring->read_idx + ring->size) % ring->size; } /** * Returns number of octets that can be read from a continuous * buffer segment (between 0 and ring->size-1). */ static inline int ring_buffer_cavail_for_read(ring_buffer_t *ring) { if (ring->write_idx >= ring->read_idx) return ring->write_idx - ring->read_idx; else return ring->size - ring->read_idx; } /** * Returns number of octets that can be written (between 0 * and ring->size-1). */ static inline int ring_buffer_avail_for_write(ring_buffer_t *ring) { if (ring->read_idx == ring->write_idx) return ring->size - 1; else return (ring->read_idx - ring->write_idx - 1 + ring->size) % ring->size; } /** * Returns number of octets that can be written to * a continuous buffer segment (between 0 and ring->size-1). */ static inline int ring_buffer_cavail_for_write(ring_buffer_t *ring) { if (ring->read_idx > ring->write_idx) return ring_buffer_avail_for_write(ring); else if (ring->read_idx == 0) return ring->size - ring->write_idx -1; else return ring->size - ring->write_idx; } /** * Moves read pointer ahead for 'n' octets. Does not care about * possible overrun. */ static inline void ring_buffer_move_read(ring_buffer_t *ring, int n) { ring->read_idx = (ring->read_idx + n) % ring->size; } /** * Moves write pointer ahead for 'n' octets. Does not care about * possible overrun. */ static inline void ring_buffer_move_write(ring_buffer_t *ring, int n) { ring->write_idx = (ring->write_idx + n) % ring->size; } #endif /* INCLUDED_SAL_RING_H */ libcmtspeechdata-2.1.1+git20160721~8efc468/test_cmtspeech.c000066400000000000000000000175251112705070200230020ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file test_cmtspeech.c * * Unit test for cmtspeech.h. */ #include #include #include #include #include #include #include "cmtspeech.h" enum TestState { TEST_STATE_INIT = 0, TEST_STATE_STARTED, TEST_STATE_WAITING_FOR_CONNECTED, TEST_STATE_WAITING_FOR_DISCONNECTED, TEST_STATE_EXIT, TEST_STATE_ERROR, TEST_STATE_LAST }; const char *test_state_strings[TEST_STATE_LAST] = { "INIT", "STARTED", "WAITING_FOR_CONNECTED", "WAITING_FOR_DISCONNECTED", "EXIT", "ERROR", }; struct test_ctx { cmtspeech_t *cmtspeech; int state; int conns; int conns_target; int errors; int warnings; int verbose; }; #define TEST_INACTIVITY_TIMEOUT_SEC 300.0f #define TEST_ROUNDS 50 /* takes around 40sec */ static sig_atomic_t global_exit_request = 0; #define PREFIX "TESTER: " /** * Returns 'a - b' in seconds. */ static float priv_timespec_diff(struct timespec *a, struct timespec *b) { return (float)(a->tv_sec + ((float)a->tv_nsec)/1000000000U) - (float)(b->tv_sec + ((float)b->tv_nsec)/1000000000U); } #define TEST_CHECK_INT(ctx, x, y) \ test_check_impl(ctx, true, x, __LINE__, #x, y) #define TEST_WARN_INT(ctx, x, y) \ test_check_impl(ctx, false, x, __LINE__, #x, y) static void test_check_impl(struct test_ctx *ctx, bool error, int x, int line, const char* check, int y) { if (!x) { if (error) ++ctx->errors; else ++ctx->warnings; fprintf(stderr, PREFIX "%s %s:%d: case '%s' with value %d (%d errors, %d warnings)\n", (error ? "FAILURE" : "WARNING"), __FILE__, line, check, y, ctx->errors, ctx->warnings); } } static void test_state_tr(struct test_ctx *ctx, int to) { printf(PREFIX "Changing tester state to %s (from %s).\n", test_state_strings[to], test_state_strings[ctx->state]); ctx->state = to; } static int link_updown_cmtspeech_events(struct test_ctx *ctx) { cmtspeech_event_t event; static int sleepind = 0; struct timespec tv[10] = { { 0, 2000000LU }, { 0, 1000000LI }, { 0, 500000LU }, { 0, 200000LU }, { 0, 2000000LU }, { 0, 3000LU }, { 0,100000000LI }, { 0, 0LU }, { 0, 0LU }, { 4, 0LU }, }; int tr; cmtspeech_read_event(ctx->cmtspeech, &event); tr = cmtspeech_event_to_state_transition(ctx->cmtspeech, &event); if (ctx->verbose) printf(PREFIX "cmtspeech event received, tr %d\n", tr); TEST_WARN_INT(ctx, (tr == CMTSPEECH_TR_1_CONNECTED || tr == CMTSPEECH_TR_2_DISCONNECTED), ctx->state); if (ctx->state == TEST_STATE_WAITING_FOR_CONNECTED && tr == CMTSPEECH_TR_1_CONNECTED) { ++ctx->conns; test_state_tr(ctx, TEST_STATE_WAITING_FOR_DISCONNECTED); cmtspeech_state_change_call_status(ctx->cmtspeech, 0); } else if (ctx->state == TEST_STATE_WAITING_FOR_DISCONNECTED && tr == CMTSPEECH_TR_2_DISCONNECTED) { if (ctx->conns < ctx->conns_target) { test_state_tr(ctx, TEST_STATE_WAITING_FOR_CONNECTED); cmtspeech_state_change_call_status(ctx->cmtspeech, 1); } else { /* note: reached end-of-test */ test_state_tr(ctx, TEST_STATE_EXIT); } } else { fprintf(stderr, PREFIX "unknown transition %d in state %d\n", tr, ctx->state); test_state_tr(ctx, TEST_STATE_ERROR); } if (ctx->verbose) printf(PREFIX "sleeping for %lds:%ldns (sleep %d/%d)\n", tv[sleepind].tv_sec, tv[sleepind].tv_nsec, sleepind, (sizeof(tv) / sizeof(struct timespec))); nanosleep(&tv[sleepind], NULL); ++sleepind; sleepind %= (sizeof(tv) / sizeof(struct timespec)); return 0; } static int link_updown_loop(struct test_ctx *ctx) { struct timespec mainloop_started_at; clock_gettime(CLOCK_MONOTONIC, &mainloop_started_at); test_state_tr(ctx, TEST_STATE_STARTED); while(ctx->state < TEST_STATE_EXIT) { struct pollfd fds[1]; struct timespec now; int pollres; float testrun_len; if (ctx->state == TEST_STATE_STARTED) { cmtspeech_state_change_call_status(ctx->cmtspeech, 1); test_state_tr(ctx, TEST_STATE_WAITING_FOR_CONNECTED); } fds[0].fd = cmtspeech_descriptor(ctx->cmtspeech); fds[0].events = POLLIN; fds[0].revents = 0; /* very verbose */ /* fprintf(stderr, "p"); */ pollres = poll(fds, 1, 5000); if (pollres > 0) { if (fds[0].revents & POLLIN) { int flags = 0; int res = cmtspeech_check_pending(ctx->cmtspeech, &flags); if (res > 0) { if (flags & CMTSPEECH_EVENT_CONTROL) { link_updown_cmtspeech_events(ctx); } } if (res < 0) { fprintf(stderr, PREFIX "cmtspeech mainloop error\n"); test_state_tr(ctx, TEST_STATE_ERROR); break; } } } clock_gettime(CLOCK_MONOTONIC, &now); testrun_len = priv_timespec_diff(&now, &mainloop_started_at); if (testrun_len > TEST_INACTIVITY_TIMEOUT_SEC && ctx->state < TEST_STATE_EXIT) { /* test call should have been answered by now */ TEST_CHECK_INT(ctx, ctx->state >= TEST_STATE_STARTED, ctx->state); fprintf(stderr, PREFIX "cmtspeech mainloop stuck after %f seconds\n", testrun_len); test_state_tr(ctx, TEST_STATE_ERROR); break; } if (global_exit_request) test_state_tr(ctx, TEST_STATE_ERROR); } if (ctx->state == TEST_STATE_ERROR) return -1; return 0; } static void handle_signal_sigint(int signr) { /* fprintf(stderr, PREFIX "SIGNAL\n"); */ if (global_exit_request) { exit(-1); } global_exit_request = 1; } static int priv_setup_signals(void) { struct sigaction sa; int res; sa.sa_handler = handle_signal_sigint; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; res = sigaction(SIGINT, &sa, NULL); if (res == -1) return -1; return res; } static struct option const opt_tbl[] = { {"verbose", 0, NULL, 'v'}, {"help", 0, NULL, 'h'}, {NULL, 0, NULL, 0} }; static void priv_usage(char *name) { fprintf(stderr, "usage: %s [options]\n", name); fprintf(stderr, "\noptions:\n\t[-v|--verbose] [-h|--help]\n"); exit(1); } static void priv_parse_options(struct test_ctx *ctx, int argc, char *argv[]) { int opt_index; int res; assert(ctx); while (res = getopt_long(argc, argv, "hv", opt_tbl, &opt_index), res != -1) { switch (res) { case 'v': ctx->verbose = 1; break; case 'h': default: priv_usage(argv[0]); break; } } } int main(int argc, char *argv[]) { struct test_ctx ctx; cmtspeech_t *cmtspeech; int res = 0; priv_setup_signals(); ctx.state = TEST_STATE_INIT; ctx.conns = 0; ctx.conns_target = TEST_ROUNDS; ctx.errors = 0; ctx.warnings = 0; ctx.verbose = 0; priv_parse_options(&ctx, argc, argv); cmtspeech_init(); cmtspeech = cmtspeech_open(); ctx.cmtspeech = cmtspeech; if (ctx.verbose) { cmtspeech_trace_toggle(CMTSPEECH_TRACE_STATE_CHANGE, true); cmtspeech_trace_toggle(CMTSPEECH_TRACE_IO, true); } if (!cmtspeech) return -1; if (link_updown_loop(&ctx)) res = -2; cmtspeech_close(cmtspeech); return res; } libcmtspeechdata-2.1.1+git20160721~8efc468/test_cmtspeech_msgs.c000066400000000000000000000273721112705070200240340ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010,2011 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file test_cmtspeech_msgs.c * * Unit test for cmtspeech_msgs.h. */ #include #include #include #include #include "cmtspeech_msgs.h" #include "cmtspeech.h" #if CMTSPEECH_BIG_ENDIAN_CMDS #define BYTE0 0 /* MSB byte */ #define BYTE1 1 #define BYTE2 2 #define BYTE3 3 /* LSB byte */ #elif CMTSPEECH_LITTLE_ENDIAN_CMDS #define BYTE0 3 /* MSB byte */ #define BYTE1 2 #define BYTE2 1 #define BYTE3 0 /* LSB byte */ #else #error "Endianess must be set." #endif START_TEST(test_speech_codec_req) { cmtspeech_cmd_t cmd; uint8_t speech_data_stream = 1; uint8_t call_user_connecting_ind = 1; uint8_t codec_info = CMTSPEECH_CODEC_INFO_AMR_NB; uint8_t cellular_info = CMTSPEECH_CELLULAR_INFO_GSM; uint8_t sample_rate = CMTSPEECH_SAMPLE_RATE_16KHZ; uint8_t data_format = CMTSPEECH_DATA_FORMAT_S16LINPCM; /* test encoding-decoding */ cmtspeech_msg_encode_speech_config_req(&cmd, speech_data_stream, call_user_connecting_ind, codec_info, cellular_info, sample_rate, data_format); fail_unless(cmtspeech_msg_get_type(cmd) == CMTSPEECH_SPEECH_CONFIG_REQ); fail_unless(cmtspeech_msg_get_domain(cmd) == CMTSPEECH_DOMAIN_CONTROL); sample_rate = CMTSPEECH_SAMPLE_RATE_NONE; cmtspeech_msg_decode_speech_config_req(cmd, NULL, NULL, NULL, NULL, &sample_rate, NULL); fail_unless(sample_rate == CMTSPEECH_SAMPLE_RATE_16KHZ); /* test with a prefilled test vector */ /* params: DataLength=10ms, SpeechDS=1, CallUCI=0, AMR-WB, GSM, 8kHz, 16bitlinpcm */ cmd.d.buf[BYTE0] = 0x31; cmd.d.buf[BYTE1] = 0x00; cmd.d.buf[BYTE2] = 0x2a; cmd.d.buf[BYTE3] = 0xd5; speech_data_stream = call_user_connecting_ind = codec_info = sample_rate = data_format = 255; cmtspeech_msg_decode_speech_config_req(cmd, &speech_data_stream, &call_user_connecting_ind, &codec_info, &cellular_info, &sample_rate, &data_format); fail_unless(speech_data_stream == 1); fail_unless(call_user_connecting_ind == 0); fail_unless(codec_info == CMTSPEECH_CODEC_INFO_AMR_WB); fail_unless(cellular_info == CMTSPEECH_CELLULAR_INFO_GSM); fail_unless(sample_rate == CMTSPEECH_SAMPLE_RATE_8KHZ); } END_TEST START_TEST(test_timing_config_ntf) { cmtspeech_cmd_t cmd; uint16_t msec = 500; uint16_t usec = 999; /* test encoding-decoding */ cmtspeech_msg_encode_timing_config_ntf(&cmd, msec, usec); fail_unless(cmtspeech_msg_get_type(cmd) == CMTSPEECH_TIMING_CONFIG_NTF); fail_unless(cmtspeech_msg_get_domain(cmd) == CMTSPEECH_DOMAIN_CONTROL); msec = 0; usec = 0; cmtspeech_msg_decode_timing_config_ntf(cmd, &msec, &usec); fail_unless(msec == 500); fail_unless(usec == 999); msec = 0; usec = 0; cmtspeech_msg_encode_timing_config_ntf(&cmd, msec, usec); msec = 500; usec = 999; cmtspeech_msg_decode_timing_config_ntf(cmd, &msec, &usec); fail_unless(msec == 0); fail_unless(usec == 0); /* test with a prefilled test vector */ cmd.d.buf[BYTE0] = 0x41; cmd.d.buf[BYTE1] = 0x06; cmd.d.buf[BYTE2] = 0xbf; cmd.d.buf[BYTE3] = 0xdb; msec = usec = 65535; cmtspeech_msg_decode_timing_config_ntf(cmd, &msec, &usec); fail_unless(msec == 431); fail_unless(usec == 987); } END_TEST START_TEST(test_ssi_config_req) { cmtspeech_cmd_t cmd; uint8_t layout = CMTSPEECH_SAMPLE_LAYOUT_SWAPPED_LE; uint8_t version = 2; uint8_t state = 1; /* test encoding-decoding */ cmtspeech_msg_encode_ssi_config_req(&cmd, layout, version, state); fail_unless(cmtspeech_msg_get_type(cmd) == CMTSPEECH_SSI_CONFIG_REQ); fail_unless(cmtspeech_msg_get_domain(cmd) == CMTSPEECH_DOMAIN_CONTROL); state = 0; version = 0; layout = 0; fail_unless(cmtspeech_msg_decode_ssi_config_req(cmd, &layout, &version, &state) == 0); fail_unless(state == 1); fail_unless(version == 2); fail_unless(layout == CMTSPEECH_SAMPLE_LAYOUT_SWAPPED_LE); /* test with a prefilled test vector */ cmd.d.buf[BYTE0] = 0x21; cmd.d.buf[BYTE1] = 0x00; cmd.d.buf[BYTE2] = 0x02; cmd.d.buf[BYTE3] = 0x00; cmtspeech_msg_decode_ssi_config_req(cmd, &layout, &version, &state); fail_unless(cmtspeech_msg_get_type(cmd) == CMTSPEECH_SSI_CONFIG_REQ); fail_unless(layout == CMTSPEECH_SAMPLE_LAYOUT_INORDER_LE); } END_TEST START_TEST(test_ssi_config_resp) { cmtspeech_cmd_t cmd; uint8_t layout = CMTSPEECH_SAMPLE_LAYOUT_SWAPPED_LE; uint8_t state = 2; /* test encoding-decoding */ cmtspeech_msg_encode_ssi_config_resp(&cmd, layout, state); fail_unless(cmtspeech_msg_get_type(cmd) == CMTSPEECH_SSI_CONFIG_RESP); fail_unless(cmtspeech_msg_get_domain(cmd) == CMTSPEECH_DOMAIN_CONTROL); state = 0; layout = 0; fail_unless(cmtspeech_msg_decode_ssi_config_resp(cmd, &layout, &state) == 0); fail_unless(state == 2); fail_unless(layout == CMTSPEECH_SAMPLE_LAYOUT_SWAPPED_LE); } END_TEST START_TEST(test_reset_conn_resp) { cmtspeech_cmd_t cmd; /* test encoding-decoding */ cmtspeech_msg_encode_reset_conn_resp(&cmd); fail_unless(cmtspeech_msg_get_type(cmd) == CMTSPEECH_RESET_CONN_RESP); fail_unless(cmtspeech_msg_get_domain(cmd) == CMTSPEECH_DOMAIN_CONTROL); /* test with a prefilled test vector */ cmd.d.buf[BYTE0] = 0x11; cmd.d.buf[BYTE1] = 0x00; cmd.d.buf[BYTE2] = 0x00; cmd.d.buf[BYTE3] = 0x00; fail_unless(cmtspeech_msg_get_type(cmd) == CMTSPEECH_RESET_CONN_RESP); } END_TEST START_TEST(test_reset_conn_req) { cmtspeech_cmd_t cmd; /* test encoding-decoding */ cmtspeech_msg_encode_reset_conn_req(&cmd); fail_unless(cmtspeech_msg_get_type(cmd) == CMTSPEECH_RESET_CONN_REQ); fail_unless(cmtspeech_msg_get_domain(cmd) == CMTSPEECH_DOMAIN_CONTROL); /* test with a prefilled test vector */ cmd.d.buf[BYTE0] = 0x01; cmd.d.buf[BYTE1] = 0x00; cmd.d.buf[BYTE2] = 0x00; cmd.d.buf[BYTE3] = 0x00; fail_unless(cmtspeech_msg_get_type(cmd) == CMTSPEECH_RESET_CONN_REQ); } END_TEST START_TEST(test_ul_data_frame) { uint8_t buf[255] = { 0 }; uint16_t frame_counter = 65535; uint8_t data_length = 255; uint8_t sample_rate = 255; uint8_t data_type = 255; /* test encoding-decoding */ cmtspeech_msg_encode_ul_data_header(buf, 255, 12345, CMTSPEECH_DATA_LENGTH_10MS, CMTSPEECH_SAMPLE_RATE_8KHZ, CMTSPEECH_DATA_TYPE_INVALID); cmtspeech_msg_decode_ul_data_header(buf, 255, &frame_counter, &data_length, &sample_rate, &data_type); fail_unless(frame_counter == 12345); fail_unless(data_length == CMTSPEECH_DATA_LENGTH_10MS); fail_unless(sample_rate == CMTSPEECH_SAMPLE_RATE_8KHZ); fail_unless(data_type == CMTSPEECH_DATA_TYPE_INVALID); /* test with a prefilled test vector */ uint8_t testbuf[4]; /* params: frame counter = 0xabcd, DataLength=20ms, SR=16kHz, valid data */ testbuf[BYTE0] = 0xab; testbuf[BYTE1] = 0xcd; testbuf[BYTE2] = 0x00; testbuf[BYTE3] = 0x2a; frame_counter = 65535; data_length = sample_rate = data_type = 255; cmtspeech_msg_decode_ul_data_header(testbuf, 4, &frame_counter, &data_length, &sample_rate, &data_type); fail_unless(frame_counter == 0xabcd); fail_unless(data_length == CMTSPEECH_DATA_LENGTH_20MS); fail_unless(sample_rate == CMTSPEECH_SAMPLE_RATE_16KHZ); fail_unless(data_type == CMTSPEECH_DATA_TYPE_VALID); } END_TEST START_TEST(test_dl_data_frame) { uint8_t buf[255] = { 0 }; struct { uint16_t frame_counter; uint8_t sbc_flags; uint8_t data_length; uint8_t sample_rate; uint8_t codec_sample_rate; uint8_t data_type; } p; memset(&p, 0xff, sizeof(p)); /* test encoding-decoding */ cmtspeech_msg_encode_dl_data_header(buf, sizeof(buf), 12345, CMTSPEECH_SPC_FLAGS_DTX_USED, CMTSPEECH_DATA_LENGTH_10MS, CMTSPEECH_SAMPLE_RATE_8KHZ, CMTSPEECH_DATA_TYPE_INVALID); cmtspeech_msg_decode_dl_data_header(buf, 255, &p.frame_counter, &p.sbc_flags, &p.data_length, &p.sample_rate, &p.data_type); fail_unless(p.frame_counter == 12345); fail_unless(p.sbc_flags == CMTSPEECH_SPC_FLAGS_DTX_USED); fail_unless(p.data_length == CMTSPEECH_DATA_LENGTH_10MS); fail_unless(p.sample_rate == CMTSPEECH_SAMPLE_RATE_8KHZ); fail_unless(p.data_type == CMTSPEECH_DATA_TYPE_INVALID); cmtspeech_msg_encode_dl_data_header_v5(buf, sizeof(buf), 54321, CMTSPEECH_SPC_FLAGS_MUTE, CMTSPEECH_DATA_LENGTH_10MS, CMTSPEECH_SAMPLE_RATE_8KHZ, CMTSPEECH_SAMPLE_RATE_16KHZ, CMTSPEECH_DATA_TYPE_INVALID); cmtspeech_msg_decode_dl_data_header_v5(buf, 255, &p.frame_counter, &p.sbc_flags, &p.data_length, &p.sample_rate, &p.codec_sample_rate, &p.data_type); fail_unless(p.frame_counter == 54321); fail_unless(p.sbc_flags == CMTSPEECH_SPC_FLAGS_MUTE); fail_unless(p.data_length == CMTSPEECH_DATA_LENGTH_10MS); fail_unless(p.sample_rate == CMTSPEECH_SAMPLE_RATE_8KHZ); fail_unless(p.data_type == CMTSPEECH_DATA_TYPE_INVALID); /* test with a prefilled test vector */ /* params: frame counter = 0xabcd, SPC-bfi, DataLength=20ms, SR=16kHz, CSR=16kHz, valid data */ uint8_t testbuf[4]; testbuf[BYTE0] = 0xab; testbuf[BYTE1] = 0xcd; testbuf[BYTE2] = 0x50; testbuf[BYTE3] = 0xa9; memset(&p, 0xff, sizeof(p)); cmtspeech_msg_decode_dl_data_header(testbuf, 4, &p.frame_counter, &p.sbc_flags, &p.data_length, &p.sample_rate, &p.data_type); fail_unless(p.frame_counter == 0xabcd); fail_unless(p.sbc_flags & CMTSPEECH_SPC_FLAGS_BFI); fail_unless(p.sbc_flags & CMTSPEECH_SPC_FLAGS_DTX_USED); fail_unless(p.sbc_flags & CMTSPEECH_SPC_FLAGS_BFI); fail_unless(p.data_length == CMTSPEECH_DATA_LENGTH_20MS); fail_unless(p.sample_rate == CMTSPEECH_SAMPLE_RATE_16KHZ); fail_unless(p.data_type == CMTSPEECH_DATA_TYPE_INVALID); memset(&p, 0xff, sizeof(p)); cmtspeech_msg_decode_dl_data_header_v5(testbuf, 4, &p.frame_counter, &p.sbc_flags, &p.data_length, &p.sample_rate, &p.codec_sample_rate, &p.data_type); fail_unless(p.frame_counter == 0xabcd); fail_unless(p.sbc_flags & CMTSPEECH_SPC_FLAGS_BFI); fail_unless(p.sbc_flags & CMTSPEECH_SPC_FLAGS_DTX_USED); fail_unless((p.sbc_flags & ~(CMTSPEECH_SPC_FLAGS_DTX_USED | CMTSPEECH_SPC_FLAGS_BFI)) == 0); fail_unless(p.data_length == CMTSPEECH_DATA_LENGTH_20MS); fail_unless(p.sample_rate == CMTSPEECH_SAMPLE_RATE_16KHZ); fail_unless(p.codec_sample_rate == CMTSPEECH_SAMPLE_RATE_16KHZ); fail_unless(p.data_type == CMTSPEECH_DATA_TYPE_INVALID); } END_TEST Suite *ssi_msgs_suite(void) { Suite *suite = suite_create("ssi_msgs"); TCase *control = tcase_create("control"); TCase *data = tcase_create("data"); tcase_add_test(control, test_speech_codec_req); tcase_add_test(control, test_timing_config_ntf); tcase_add_test(control, test_ssi_config_req); tcase_add_test(control, test_ssi_config_resp); tcase_add_test(control, test_reset_conn_req); tcase_add_test(control, test_reset_conn_resp); tcase_add_test(data, test_ul_data_frame); tcase_add_test(data, test_dl_data_frame); suite_add_tcase(suite, control); suite_add_tcase(suite, data); return suite; } int main(int argc, char *argv[]) { int nr_failed; Suite *suite = ssi_msgs_suite(); SRunner *runner = srunner_create(suite); srunner_set_xml(runner, "/tmp/result.xml"); srunner_run_all(runner, CK_NORMAL); nr_failed = srunner_ntests_failed(runner); srunner_free(runner); return (nr_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libcmtspeechdata-2.1.1+git20160721~8efc468/test_ring.c000066400000000000000000000075611112705070200217650ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file test_ring.c * * Unit test for sal_ring.h. */ #include #include #include #include "sal_ring.h" START_TEST(test_ring_read) { ring_buffer_t ringbuf; ring_buffer_init(&ringbuf, NULL, 16); fail_unless(ring_buffer_avail_for_read(&ringbuf) == 0); fail_unless(ring_buffer_cavail_for_read(&ringbuf) == 0); ringbuf.read_idx = 15; ringbuf.write_idx = 0; fail_unless(ring_buffer_avail_for_read(&ringbuf) == 1); fail_unless(ring_buffer_cavail_for_read(&ringbuf) == 1); ringbuf.read_idx = 15; ringbuf.write_idx = 2; fail_unless(ring_buffer_avail_for_read(&ringbuf) == 3); fail_unless(ring_buffer_cavail_for_read(&ringbuf) == 1); ringbuf.read_idx = 1; ringbuf.write_idx = 2; fail_unless(ring_buffer_avail_for_read(&ringbuf) == 1); fail_unless(ring_buffer_cavail_for_read(&ringbuf) == 1); ringbuf.read_idx = 0; ringbuf.write_idx = 15; fail_unless(ring_buffer_avail_for_read(&ringbuf) == 15); fail_unless(ring_buffer_cavail_for_read(&ringbuf) == 15); } END_TEST START_TEST(test_ring_write) { ring_buffer_t ringbuf; ring_buffer_init(&ringbuf, NULL, 16); fail_unless(ring_buffer_avail_for_write(&ringbuf) == 15); fail_unless(ring_buffer_cavail_for_write(&ringbuf) == 15); ringbuf.read_idx = 0; ringbuf.write_idx = 0; fail_unless(ring_buffer_avail_for_write(&ringbuf) == 15); fail_unless(ring_buffer_cavail_for_write(&ringbuf) == 15); ringbuf.read_idx = 8; ringbuf.write_idx = 8; fail_unless(ring_buffer_avail_for_write(&ringbuf) == 15); fail_unless(ring_buffer_cavail_for_write(&ringbuf) == 8); ringbuf.read_idx = 15; ringbuf.write_idx = 0; fail_unless(ring_buffer_avail_for_write(&ringbuf) == 14); fail_unless(ring_buffer_cavail_for_write(&ringbuf) == 14); ringbuf.read_idx = 15; ringbuf.write_idx = 2; fail_unless(ring_buffer_avail_for_write(&ringbuf) == 12); fail_unless(ring_buffer_cavail_for_write(&ringbuf) == 12); ringbuf.read_idx = 0; ringbuf.write_idx = 1; fail_unless(ring_buffer_avail_for_write(&ringbuf) == 14); fail_unless(ring_buffer_cavail_for_write(&ringbuf) == 14); ringbuf.read_idx = 1; ringbuf.write_idx = 2; fail_unless(ring_buffer_avail_for_write(&ringbuf) == 14); fail_unless(ring_buffer_cavail_for_write(&ringbuf) == 14); ringbuf.read_idx = 0; ringbuf.write_idx = 15; fail_unless(ring_buffer_avail_for_write(&ringbuf) == 0); fail_unless(ring_buffer_cavail_for_write(&ringbuf) == 0); } END_TEST Suite *ring_suite(void) { Suite *suite = suite_create("ring_buffer"); TCase *ring = tcase_create("ring_buffer"); tcase_add_test(ring, test_ring_read); tcase_add_test(ring, test_ring_write); suite_add_tcase(suite, ring); return suite; } int main(int argc, char *argv[]) { int nr_failed; Suite *suite = ring_suite(); SRunner *runner = srunner_create(suite); srunner_set_xml(runner, "/tmp/result.xml"); srunner_run_all(runner, CK_NORMAL); nr_failed = srunner_ntests_failed(runner); srunner_free(runner); return (nr_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } libcmtspeechdata-2.1.1+git20160721~8efc468/utils/000077500000000000000000000000001112705070200207525ustar00rootroot00000000000000libcmtspeechdata-2.1.1+git20160721~8efc468/utils/cmtspeech_ofono_test.c000066400000000000000000000411321112705070200253310ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech_ofono_test.c * * Tool that listens to org.ofono DBus messages for voice call * state, and when call server actives (i.e. a voice call is * established), the tool sets up a loopback for voice data path, * routing call downlink to uplink. * * Note: due to protocol timing limitations, this test does not work * in 2G/GSM mode. */ /** * General list of TODO items: * - */ #include #include #include #include #include #include #include #include #include #include #include #include #include struct test_ctx { DBusConnection* dbus_conn; int dbus_fd; DBusWatch *dbus_watch; bool call_server_status; int verbose; cmtspeech_t *cmtspeech; pa_simple *source; pa_simple *sink; int data_through; }; #define PREFIX "cmtspeech_ofono_test: " static sig_atomic_t global_exit_request = 0; #define INFO(x) \ do { if (ctx->verbose > 0) x; } while(0) #define DEBUG(x) \ do { if (ctx->verbose > 1) x; } while(0) static dbus_bool_t priv_add_cb(DBusWatch *watch, void *data) { struct test_ctx *ctx = (struct test_ctx*)data; int fd = dbus_watch_get_unix_fd(watch); ctx->dbus_fd = fd; ctx->dbus_watch = watch; DEBUG(fprintf(stderr, PREFIX "priv_add_cb: socket %d, watch %p (tracking %p).\n", fd, watch, ctx->dbus_watch)); return TRUE; } static void priv_remove_cb(DBusWatch *watch, void *data) { struct test_ctx *ctx = (struct test_ctx*)data; DEBUG(fprintf(stderr, PREFIX "priv_remove_cb: (%p).\n", (void*)watch)); if (ctx->dbus_watch == watch) { ctx->dbus_watch = NULL; ctx->dbus_fd = -1; } } static void priv_toggled_cb(DBusWatch *watch, void *data) { struct test_ctx *ctx = (struct test_ctx*)data; dbus_bool_t enabled = dbus_watch_get_enabled(watch); DEBUG(fprintf(stderr, PREFIX "priv_toggled_cb: (%p) enabled=%d.\n", (void*)watch, enabled)); if (ctx->dbus_watch == watch) { if (enabled == TRUE) ctx->dbus_fd = dbus_watch_get_unix_fd(watch); else ctx->dbus_fd = -1; } } static void priv_free_data_cb(void *data) { /* no-op */ } static inline void priv_add_match(DBusConnection *conn, const char* match, int *errs) { DBusError dbus_error; dbus_error_init(&dbus_error); dbus_bus_add_match(conn, match, &dbus_error); if (dbus_error_is_set(&dbus_error) == TRUE) ++(*errs); } DBusConnection *test_dbus_make_connection(struct test_ctx *ctx, DBusBusType dbus_type) { DBusConnection *conn; DBusError dbus_error; dbus_error_init(&dbus_error); conn = dbus_bus_get(dbus_type, &dbus_error); if (dbus_error_is_set(&dbus_error) != TRUE) { DEBUG(fprintf(stderr, PREFIX "Connection established to DBus (%d).\n", (int)dbus_type)); } else { fprintf(stderr, PREFIX "ERROR: unable to connect to DBus\n"); } return conn; } /** * Sets up the DBus connection. */ static int test_dbus_init(struct test_ctx *ctx, DBusBusType dbus_type) { DBusConnection *conn; int add_match_errs = 0; ctx->call_server_status = 0; conn = test_dbus_make_connection(ctx, dbus_type); if (conn == NULL) return -1; dbus_connection_set_watch_functions(conn, priv_add_cb, priv_remove_cb, priv_toggled_cb, ctx, priv_free_data_cb); priv_add_match(conn, "type='signal',interface='org.ofono.AudioSettings'", &add_match_errs); if (add_match_errs) { dbus_connection_unref(conn); return -1; } dbus_connection_flush(conn); ctx->dbus_conn = conn; return 0; } static void test_dbus_release(struct test_ctx *ctx) { if (ctx->dbus_conn) { dbus_connection_unref(ctx->dbus_conn); ctx->dbus_conn = NULL; } } #if 0 static void flush_input(struct test_ctx *ctx) { char scratch[10240]; int total = 0; fprintf(stderr, "Flushing input...\n"); if (!ctx->sink_fd) return; while(1) { int num; num = read(ctx->source_fd, scratch, 10240); if (num == -1) break; total += num; } fprintf(stderr, "Flushing input (%d)\n", total); } #endif /* FIXME: Hmm. That makes no sense. Is it rate = 8000, channels = 1? */ /* FIXME: requesting 8000 crashes pulseaudio. */ static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 4000, .channels = 2 }; static const pa_buffer_attr pa_attr = { .fragsize = (uint32_t) 1024, .maxlength = (uint32_t) -1, .minreq = (uint32_t) 1024, .prebuf = (uint32_t) -1, .tlength = (uint32_t) 1024, /* fragsize / tlength can be 4096 -> pulseaudio CPU drops from 33% CPU to 10%, but latency can be heard */ }; static void start_sink(struct test_ctx *ctx) { int error; /* The sample type to use */ if (!(ctx->sink = pa_simple_new(NULL, "libcmtspeech_ofono", PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &pa_attr, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); exit(1); } } static void start_source(struct test_ctx *ctx) { int error; /* Create the recording stream */ if (!(ctx->source = pa_simple_new(NULL, "libcmtspeech_ofono", PA_STREAM_RECORD, NULL, "record", &ss, NULL, &pa_attr, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); exit(1); } } static void stop_source(struct test_ctx *ctx) { if (ctx->source) pa_simple_free(ctx->source); ctx->source = NULL; } static void stop_sink(struct test_ctx *ctx) { if (ctx->sink) pa_simple_free(ctx->sink); ctx->sink = NULL; } static void report_sound(struct test_ctx *ctx) { pa_usec_t latency_p = -999999, latency_r = -999999; int error; if (ctx->sink) if ((latency_p = pa_simple_get_latency(ctx->sink, &error)) == (pa_usec_t) -1) { fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error)); exit(1); } if (ctx->source) if ((latency_r = pa_simple_get_latency(ctx->source, &error)) == (pa_usec_t) -1) { fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error)); exit(1); } fprintf(stderr, "playback %10.0f usec, record %10.0f usec \n", (float)latency_p, (float)latency_r); } static bool test_handle_dbus_ofono(struct test_ctx *ctx, DBusMessage *msg) { const char* property = NULL; DBusError dbus_error = DBUS_ERROR_INIT; bool parse_ok = false; if (dbus_message_is_signal(msg, "org.ofono.AudioSettings", "PropertyChanged")) { dbus_message_get_args(msg, &dbus_error, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); DEBUG(fprintf(stderr, PREFIX "received ofono AudioSettings change, params name='%s'\n", property)); if (strcmp(property, "Active") == 0) { DBusMessageIter i; int type; dbus_message_iter_init(msg, &i); dbus_message_iter_next(&i); type = dbus_message_iter_get_arg_type(&i); if (type == DBUS_TYPE_VARIANT) { DBusMessageIter j; dbus_message_iter_recurse(&i, &j); type = dbus_message_iter_get_arg_type(&j); if (type == 'b') { dbus_bool_t state, old_state = ctx->call_server_status; dbus_message_iter_get_basic(&j, &state); if (state != old_state) { INFO(fprintf(stderr, PREFIX "org.ofono.AudioSettings.Active to %d.\n", state)); #if 0 if (state == 1) { start_sound(ctx); } if (state == 0) { stop_sound(ctx); } #endif cmtspeech_state_change_call_status(ctx->cmtspeech, state); ctx->call_server_status = state; } parse_ok = true; } } if (parse_ok != true) fprintf(stderr, PREFIX "ERROR: error parsing org.ofono.AudioSettings property '%s'\n", property); } else { fprintf(stderr, PREFIX "ERROR: unsupported org.ofono.AudioSettings property '%s'\n", property); } } return parse_ok; } static int test_handle_dbus_message(struct test_ctx *ctx, DBusMessage *msg) { int res = 0; const char* dbusif = dbus_message_get_interface(msg); DEBUG(fprintf(stderr, PREFIX "got message to if:%s, member:%s.\n", dbusif, dbus_message_get_member(msg))); if (strstr(dbusif, "org.ofono.")) { test_handle_dbus_ofono(ctx, msg); } else INFO(fprintf(stderr, PREFIX "unknown/ignored signal: if=%s, member=%s.\n", dbusif, dbus_message_get_member(msg))); return res; } static void handle_signal_sigint(int signr) { /* fprintf(stderr, PREFIX "SIGNAL\n"); */ if (global_exit_request) { exit(-1); } global_exit_request = 1; } static int priv_setup_signals(void) { struct sigaction sa; int res; sa.sa_handler = handle_signal_sigint; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; res = sigaction(SIGINT, &sa, NULL); if (res == -1) return -1; return res; } static struct option const opt_tbl[] = { {"verbose", 0, NULL, 'v'}, {"help", 0, NULL, 'h'}, {"audio", 0, NULL, 'a'}, {NULL, 0, NULL, 0} }; static void priv_usage(char *name) { fprintf(stderr, "usage: %s [options]\n", name); fprintf(stderr, "\noptions:\n\t[-v|--verbose] [-h|--help]\n"); exit(1); } static void priv_parse_options(struct test_ctx *ctx, int argc, char *argv[]) { int opt_index; int res; assert(ctx); while (res = getopt_long(argc, argv, "hva", opt_tbl, &opt_index), res != -1) { switch (res) { case 'v': ++ctx->verbose; fprintf(stderr, PREFIX "Increasing verbosity to %d.\n", ctx->verbose); break; case 'a': fprintf(stderr, "Enabling audio path\n"); ctx->source = 0; ctx->sink = 0; ctx->data_through = 0; #if 0 { int flags = fcntl(ctx->source_fd, F_GETFL, 0); fcntl(ctx->source_fd, F_SETFL, flags | O_NONBLOCK); } #endif break; case 'h': default: priv_usage(argv[0]); break; } } } static void test_handle_cmtspeech_data(struct test_ctx *ctx) { cmtspeech_buffer_t *dlbuf, *ulbuf; char scratch[10240]; int res, error, num; int state = cmtspeech_protocol_state(ctx->cmtspeech); int active_ul = (state == CMTSPEECH_STATE_ACTIVE_DLUL); int active_dl = (state == CMTSPEECH_STATE_ACTIVE_DLUL) || (state == CMTSPEECH_STATE_ACTIVE_DL); int loops; while (ctx->source && active_ul) { pa_usec_t latency_r; if ((latency_r = pa_simple_get_latency(ctx->source, &error)) == (pa_usec_t) -1) { fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error)); exit(1); } if (latency_r < 100000) { fprintf(stderr, "...skip latency (%d)\n", latency_r); break; } if (latency_r > 1000000) { fprintf(stderr, "...flush latency (%d)\n", latency_r); num = pa_simple_read(ctx->source, scratch, 320, &error); if (num < 0){ fprintf(stderr, __FILE__": error during flushing: %s\n", pa_strerror(error)); exit(1); } if ((latency_r = pa_simple_get_latency(ctx->source, &error)) == (pa_usec_t) -1) { fprintf(stderr, __FILE__": pa_simple_get_latency() failed: %s\n", pa_strerror(error)); exit(1); } } res = cmtspeech_ul_buffer_acquire(ctx->cmtspeech, &ulbuf); if (res != 0) break; memset(ulbuf->payload, 0, ulbuf->pcount); num = pa_simple_read(ctx->source, ulbuf->payload, ulbuf->pcount, &error); if (num < 0) { fprintf(stderr, "error reading from source (%d), error %s\n", ulbuf->pcount, pa_strerror(error)); break; } ctx->data_through += ulbuf->pcount; res = cmtspeech_ul_buffer_release(ctx->cmtspeech, ulbuf); if (res != 0) { fprintf(stderr, "Could notrelease ulbuf, says (%d)\n", res); break; } break; } if (!active_dl) return; res = cmtspeech_dl_buffer_acquire(ctx->cmtspeech, &dlbuf); if (res != 0) { return; } DEBUG(fprintf(stderr, PREFIX "Received a DL packet (%u bytes).\n", dlbuf->count)); /* */ if (!ctx->sink) { fprintf(stderr, PREFIX "have packet but no sink?.\n"); exit(1); } num = pa_simple_write(ctx->sink, dlbuf->payload, dlbuf->pcount, &error); if (num < 0) { fprintf(stderr, "Error writing to sink, %d, error %s\n", dlbuf->pcount, pa_strerror(error)); } report_sound(ctx); res = cmtspeech_dl_buffer_release(ctx->cmtspeech, dlbuf); } static int test_handle_cmtspeech_control(struct test_ctx *ctx) { cmtspeech_event_t cmtevent; int state_tr = CMTSPEECH_TR_INVALID; cmtspeech_read_event(ctx->cmtspeech, &cmtevent); DEBUG(fprintf(stderr, PREFIX "read cmtspeech event %d.\n", cmtevent.msg_type)); state_tr = cmtspeech_event_to_state_transition(ctx->cmtspeech, &cmtevent); DEBUG(fprintf(stderr, PREFIX "state transition %d.\n", state_tr)); switch(state_tr) { case CMTSPEECH_TR_INVALID: fprintf(stderr, PREFIX "ERROR: invalid state transition\n"); break; case CMTSPEECH_TR_1_CONNECTED: case CMTSPEECH_TR_2_DISCONNECTED: break; case CMTSPEECH_TR_3_DL_START: /* Start audio playback here ? */ start_sink(ctx); break; case CMTSPEECH_TR_4_DLUL_STOP: stop_source(ctx); stop_sink(ctx); break; /* Stop audio ? */ case CMTSPEECH_TR_5_PARAM_UPDATE: /* no-op */ break; case CMTSPEECH_TR_6_TIMING_UPDATE: case CMTSPEECH_TR_7_TIMING_UPDATE: INFO(printf(PREFIX "WARNING: modem UL timing update ignored\n")); case CMTSPEECH_TR_10_RESET: break; case CMTSPEECH_TR_11_UL_STOP: stop_source(ctx); break; case CMTSPEECH_TR_12_UL_START: start_source(ctx); break; /* Start audio record? */ /* no-op */ default: assert(0); } return 0; } static int test_mainloop(struct test_ctx *ctx) { const int cmt = 0; const int dbus = 1; struct pollfd fds[2]; int res = 0; fds[cmt].fd = cmtspeech_descriptor(ctx->cmtspeech); fds[cmt].events = POLLIN; assert(fds[cmt].fd >= 0); while(!global_exit_request) { int count = 1, pollres; if (ctx->dbus_fd >= 0) { fds[dbus].fd = ctx->dbus_fd; assert(fds[dbus].fd >= 0); fds[dbus].events = POLLIN; count = 2; } pollres = poll(fds, count, -1); DEBUG(fprintf(stderr, "poll returned %d (count:%d, cmt:%02X, dbus:%02X)\n", pollres, count, fds[cmt].revents, fds[dbus].revents)); /* Should we poll for audio, too? */ if (pollres > 0) { if (fds[cmt].revents) { int flags = 0, res = cmtspeech_check_pending(ctx->cmtspeech, &flags); if (res > 0) { if (flags & CMTSPEECH_EVENT_DL_DATA) test_handle_cmtspeech_data(ctx); if (flags & CMTSPEECH_EVENT_CONTROL) test_handle_cmtspeech_control(ctx); } } if (count > 1 && fds[dbus].revents) { DBusMessage *msg; if (dbus_connection_get_dispatch_status(ctx->dbus_conn) == DBUS_DISPATCH_DATA_REMAINS) dbus_connection_dispatch(ctx->dbus_conn); dbus_watch_handle(ctx->dbus_watch, DBUS_WATCH_READABLE); msg = dbus_connection_pop_message(ctx->dbus_conn); while (msg) { test_handle_dbus_message(ctx, msg); dbus_message_unref(msg); msg = dbus_connection_pop_message(ctx->dbus_conn); } } } else if (pollres < 0) { res = -1; break; } } return res; } int main(int argc, char *argv[]) { DBusBusType dbus_type = DBUS_BUS_SYSTEM; struct test_ctx ctx0; struct test_ctx *ctx = &ctx0; int res = 0; fprintf(stderr, "NFS sucks, version 0.0.1\n"); priv_setup_signals(); ctx->dbus_conn = NULL; ctx->dbus_fd = -1; ctx->dbus_watch = NULL; ctx->verbose = 0; priv_parse_options(ctx, argc, argv); cmtspeech_init(); test_dbus_init(ctx, dbus_type); if (ctx->verbose > 0) { cmtspeech_trace_toggle(CMTSPEECH_TRACE_STATE_CHANGE, true); cmtspeech_trace_toggle(CMTSPEECH_TRACE_IO, true); if (ctx->verbose > 1) { cmtspeech_trace_toggle(CMTSPEECH_TRACE_DEBUG, true); } } ctx->cmtspeech = cmtspeech_open(); if (!ctx->cmtspeech) { fprintf(stderr, "ERROR: unable to open libcmtspeechdata instance\n"); return -1; } INFO(fprintf(stderr, PREFIX "Setup succesful, entering mainloop.\n")); res = test_mainloop(ctx); cmtspeech_close(ctx->cmtspeech); test_dbus_release(ctx); INFO(fprintf(stderr, PREFIX "Completed, exiting (%d).\n", res)); return res; } libcmtspeechdata-2.1.1+git20160721~8efc468/utils/cmtspeech_ramp_test.c000066400000000000000000000064131112705070200251530ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file cmtspeech_ramp_test.c * * Tool that opens a libcmtspeechdata instance, performs * a loop of tests with the TEST_RAMP_PING interface, and * closes the instance. */ /** * General list of TODO items: * - */ #include #include #include static void priv_dump_ramp_frame(uint8_t *slotbuf, unsigned int slot_size) { unsigned int i; /* note: unlike all other traces, this is printed directly to stdout */ for(i = 0; i < slot_size; i += 4) { printf("%02X:%02X:%02X:%02X ", slotbuf[i], slotbuf[i+1], slotbuf[i+2], slotbuf[i+3]); /* note: print header on a separate line */ if (i == 0) printf ("(32 bit frame header, payload follows)\n"); else if ((i + 4) % 16 == 4) printf("\n"); } if ((i + 4) % 16 != 4) printf("\n"); } int main(int argc, char *argv[]) { struct pollfd fds[1]; cmtspeech_t *cmtspeech; int res = 0, i, fd; int pollres, test_msgs = 0; const int send_test_msgs = 3; const uint8_t test_frame_size = 81; cmtspeech_init(); cmtspeech = cmtspeech_open(); if (!cmtspeech) { fprintf(stderr, "ERROR: unable to open libcmtspeechdata instance\n"); return -1; } fd = cmtspeech_descriptor(cmtspeech); if (fd < 0) { fprintf(stderr, "ERROR: invalid libcmtspeechdata descriptor.\n"); return -2; } for (i = 0;; i++) { if (cmtspeech_protocol_state(cmtspeech) == CMTSPEECH_STATE_DISCONNECTED) { if (++test_msgs == send_test_msgs) break; cmtspeech_test_data_ramp_req(cmtspeech, 0xaa /*(uint8_t)i*/, test_frame_size); } fds[0].fd = fd; pollres = poll(fds, 1, 20); printf("poll returned %d (iter %d).\n", pollres, i); if (pollres == 1) { int flags = 0, res = cmtspeech_check_pending(cmtspeech, &flags); if (res > 0) { if (flags & CMTSPEECH_EVENT_DL_DATA) { cmtspeech_buffer_t *buf; res = cmtspeech_dl_buffer_acquire(cmtspeech, &buf); if (res == 0) { printf("Received a test ramp packet (%u bytes). Dumping its contents.", buf->count); priv_dump_ramp_frame(buf->data, buf->count); res = cmtspeech_dl_buffer_release(cmtspeech, buf); } } if (flags & CMTSPEECH_EVENT_CONTROL) { cmtspeech_event_t event; cmtspeech_read_event(cmtspeech, &event); printf("read event %d.\n", event.msg_type); } } } else if (pollres < 0) break; } cmtspeech_close(cmtspeech); return res; } libcmtspeechdata-2.1.1+git20160721~8efc468/utils/send_cmtspeech_reset.c000066400000000000000000000044751112705070200253160ustar00rootroot00000000000000/* * This file is part of libcmtspeechdata. * * Copyright (C) 2008,2009,2010 Nokia Corporation. * * Contact: Kai Vehmanen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA */ /** @file send_server_status.c * * Tool that opens a libcmtspeechdata instance, sends a protocol * reset, and closes the instance. */ /** * General list of TODO items: * - */ #include #include #include int main(int argc, char *argv[]) { struct pollfd fds[1]; cmtspeech_t *cmtspeech; int res = 0; cmtspeech_init(); cmtspeech = cmtspeech_open(); if (!cmtspeech) { fprintf(stderr, "ERROR: unable to open libcmtspeechdata instance\n"); return -1; } cmtspeech_state_change_error(cmtspeech); fds[0].fd = cmtspeech_descriptor(cmtspeech); if (fds[0].fd >= 0) { int tries; int pollres = 0; for(tries = 0; tries < 3; tries++) { pollres = poll(fds, 1, 1); printf("poll for driver reset returned %d.\n", pollres); if (pollres == 1) { int flags = 0, res = cmtspeech_check_pending(cmtspeech, &flags); if (res > 0) { cmtspeech_event_t event; cmtspeech_read_event(cmtspeech, &event); if (event.msg_type == CMTSPEECH_EVENT_RESET) { printf("driver ack'ed the reset, exiting.\n"); break; } } } else if (pollres < 0) break; } if (pollres < 0 || tries == 3) { fprintf(stderr, "ERROR: no response received to libcmtspeechdata reset.\n"); res = -1; } } else { fprintf(stderr, "ERROR: invalid libcmtspeechdata descriptor.\n"); res = -2; } cmtspeech_close(cmtspeech); return res; }