📄 beaudio.cxx
字号:
/* * beaudio.cxx * * Sound driver implementation. * * Portable Windows Library * * Copyright (c) 1993-2001 Equivalence Pty. Ltd. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Equivalence Pty. Ltd. * * Portions are Copyright (C) 1993 Free Software Foundation, Inc. * All Rights Reserved. * * Contributor(s): * Yuri Kiryanov, ykiryanov at users.sourceforge.net, * Jac Goudsmit <jac@be.com>. * * $Log: beaudio.cxx,v $ * Revision 1.16 2004/10/26 18:08:54 ykiryanov * Added code for old Media Kit, to be backwards compatible with R5, and Zeta ifdef * * Revision 1.15 2004/06/16 01:55:10 ykiryanov * Added usage of lastReadCount - sound capture now works * * Revision 1.14 2004/05/30 04:48:45 ykiryanov * Stable version * * Revision 1.12 2004/05/14 05:26:57 ykiryanov * Fixed dynamic cast bug * * Revision 1.11 2004/04/18 00:32:26 ykiryanov * Fized compiler choking on <dynamic_cast>. * * Revision 1.10 2004/04/02 03:29:07 ykiryanov * New improved code * * Revision 1.9 2002/02/09 00:52:01 robertj * Slight adjustment to API and documentation for volume functions. * * Revision 1.8 2002/02/07 20:57:21 dereks * add SetVolume and GetVolume methods to PSoundChannelBeOS * * Revision 1.7 2001/07/09 06:16:15 yurik * Jac Goudsmit's BeOS changes of July,6th. Cleaning up media subsystem etc. * * Revision 1.6 2000/12/16 13:08:56 rogerh * BeOS changes from Yuri Kiryanov <openh323@kiryanov.com> * * Revision 1.5 2000/04/19 00:13:52 robertj * BeOS port changes. * * Revision 1.4 1999/09/21 00:56:29 robertj * Added more sound support for BeOS (thanks again Yuri!) * * Revision 1.3 1999/06/28 09:28:02 robertj * Portability issues, especially n BeOS (thanks Yuri!) * * Revision 1.2 1999/03/05 07:03:27 robertj * Some more BeOS port changes. * * Revision 1.1 1999/03/02 05:41:59 robertj * More BeOS changes * */#include <ptlib.h>#include <ptlib/unix/ptlib/beaudio.h>PCREATE_SOUND_PLUGIN(BeOS, PSoundChannelBeOS);/////////////// Debugging stuff ///////////////#define TL (7)#define PRINT(x) //do { printf(__FILE__ ":%d %s ", __LINE__, __FUNCTION__); printf x; printf("\n"); } while(0)#define STATUS(x) // PRINT((x "=%ld", (long)dwLastError))#define PRINTCB(x) // PRINT(x)//#define SOUNDDETECT 1 define this for printed output of first pb/rec audio//#define FILEDUMP 1 define this for dumping audio to wav file// Macros and global vars for debugging#ifdef SOUNDDETECT#define DETECTVARS(buffer,numframes) short *detbuf=(short*)buffer; size_t detframes=numframes;#define DETECTSOUND() \do { \ static bool silence=true; \ if (silence) \ { \ for (size_t i=0; i<detframes; i++) \ { \ if (detbuf[i]>=255) \ { \ PRINT(("SOUND DETECTED at %p",detbuf)); \ for (size_t j=0; j<detframes && j<30; j++) \ { \ char *x; \ asprintf(&x,"%%%ds\n",(detbuf[j]>>10)+32); \ printf(x,"."); \ free(x); \ } \ silence=false; \ break; \ } \ } \ } \} while(0)#else#define DETECTVARS(buffer,numframes)#define DETECTSOUND()#endif#ifdef FILEDUMP#include "beaudio/AudioFileWriter.h"BAudioFileWriter *playwriter=NULL;BAudioFileWriter *recwriter=NULL;#endif////////////////////////////////////////////////////////////////////////////////// PSoundPSound::PSound(unsigned channels, unsigned samplesPerSecond, unsigned bitsPerSample, PINDEX bufferSize, const BYTE * buffer){ encoding = 0; SetFormat(channels, samplesPerSecond, bitsPerSample); if (buffer != NULL) { memcpy(GetPointer(bufferSize), buffer, bufferSize); }}PSound::PSound(const PFilePath & filename){ encoding = 0; // Set the default format SetFormat(1, 8000, 16); // The format is changed if the file is succesfully loaded. Load(filename);}PSound & PSound::operator=(const PBYTEArray & data){ PBYTEArray::operator=(data); return *this;}void PSound::SetFormat(unsigned channels, unsigned samplesPerSecond, unsigned bitsPerSample){ // NOTE: all constructors should call this to initialize // the local members, especially formatInfo. // Do NOT call the function with any parameter set to 0! sampleSize=bitsPerSample; sampleRate=samplesPerSecond; numChannels = channels; // We don't use the encoding member (although we could probably set it to 0=PCM) // Let the application know it shouldn't assume anything encoding = 1; // The formatInfo member to us is a media_format structure. BOOL setsize_formatInfo=formatInfo.SetSize(sizeof(media_format)); PAssert(setsize_formatInfo, "Unable to set size for sound info array"); // Initialize the media_format struct // The numbers of bits that we support here are 8, 16 or 32 bits (signed), // results for other sizes are not defined. media_format &format=*(media_format*)(const BYTE *)formatInfo; format.type = B_MEDIA_RAW_AUDIO; format.u.raw_audio = media_raw_audio_format::wildcard; format.u.raw_audio.frame_rate=(float)sampleRate; format.u.raw_audio.channel_count=numChannels; format.u.raw_audio.format=(sampleSize / 8) & 0xF; format.u.raw_audio.byte_order=B_MEDIA_HOST_ENDIAN; format.u.raw_audio.buffer_size=(channels * samplesPerSecond * (bitsPerSample/8))/10; // 1/10 sec buffer}BOOL PSound::Load(const PFilePath & filename){ // format is a reference to the formatInfo member which stores info // about the media format. This is needed for writing the data back // or for playing the sound. media_format &format=*(media_format *)(const BYTE *)formatInfo; // Create BEntry from file name BEntry entry(filename, true); if ((dwLastError=entry.InitCheck())!=B_OK) { STATUS("entry.InitCheck()"); return FALSE; } // Create entry_ref from BEntry entry_ref ref; if ((dwLastError=entry.GetRef(&ref))!=B_OK) { STATUS("entry.GetRef()"); return FALSE; } // Create BMediaFile for read access from the entry_ref BMediaFile file(&ref); if ((dwLastError=file.InitCheck())!=B_OK) { STATUS("file.InitCheck()"); return FALSE; } // Search for the first media track that can be decoded BMediaTrack *ptrack = NULL; for (int index=0; (index<file.CountTracks()) && (dwLastError==B_OK); index++) { ptrack = file.TrackAt(index); if (ptrack) { dwLastError = ptrack->InitCheck(); } else { dwLastError = B_ERROR; //todo: change error code } if (dwLastError==B_OK) { // Get media format; we're looking for a raw audio track. format.type = B_MEDIA_RAW_AUDIO; format.u.raw_audio = media_raw_audio_format::wildcard; dwLastError = ptrack->DecodedFormat(&format); if ((dwLastError==B_OK) && (format.type==B_MEDIA_RAW_AUDIO)) { break; // found a decodable track } } else { STATUS("TrackAt() failed, error"); } // if we found a track and arrived at this point, the track we found // was not decodable if (ptrack) { dwLastError=file.ReleaseTrack(ptrack); // destroys ptrack } } // if an error occurred during track scanning, leave now if (dwLastError!=B_OK) { return FALSE; } // Get a reference to the raw output format media_raw_audio_format &rawformat = format.u.raw_audio; // Fill in our fields from the format sampleSize = (rawformat.format & 0xF) * 8; numChannels = rawformat.channel_count; if (rawformat.frame_rate>0.0 && rawformat.frame_rate<=(float)0xFFFFFFFFU) { sampleRate = (unsigned)(rawformat.frame_rate); } else { // unknown or unrepresentable sample rate. // It's not really documented what we should do in this case but // it probably doesn't matter either... sampleRate = 0; } // Get the number of frames for the track and determine how much // memory we need to store the file's data // The multiplication might overflow for huge files but we don't // want to read them into memory anyway so I guess it's ok... int64 numframes = ptrack->CountFrames(); int64 framesize = numChannels * (sampleSize/8); int64 numbytes = numframes * framesize; // Set the size of the object's data area if (!SetSize(numbytes)) { PRINT(("Can't set size of sound to %Ld", numbytes)); dwLastError = B_ERROR; //todo replace by better error code return FALSE; // BMediaFile will destroy ptrack } // Read all frames into memory. NOTE: not thread safe! BYTE* dest = GetPointer(); // destination pointer int64 framecount = numframes; // number of frames left to read int64 framesread; // number of actual frames done while ((framecount!=0) && (dwLastError==B_OK)) { framesread = framecount; dwLastError = ptrack->ReadFrames(dest, &framesread); dest += framesread * framesize; framecount -= framesread; } // return true for success return (dwLastError==B_OK); // BMediaFile will destroy ptrack}BOOL PSound::Save(const PFilePath & filename){ // format is a reference to the formatInfo member which stores info // about the media format. This is needed for writing the data back // or for playing the sound. media_format &format=*(media_format *)(const BYTE *)formatInfo; // Get the file type from the file name's extension; if none, use wav PFilePathString filetype=filename.GetType(); // e.g. ".wav" if (filetype=="") { filetype="wav"; } else { filetype=filetype.Mid(1); // cut off the '.' } // Try to find the file format in BeOS's list of formats media_file_format mfi; int32 cookie=0; while ((dwLastError=get_next_file_format(&cookie, &mfi))==B_OK) { if (!strcasecmp(mfi.file_extension, (const char *)filetype)) { break; } } if (dwLastError!=B_OK) { // didn't find file format PRINT(("Couldn't find media_file_format for \"%s\"", (const char *)filetype)); return FALSE; } // Create BEntry from file name BEntry entry(filename, true); if ((dwLastError=entry.InitCheck())!=B_OK) { STATUS("entry.InitCheck()"); return FALSE; } // Create entry_ref from BEntry entry_ref ref; if ((dwLastError=entry.GetRef(&ref))!=B_OK) { STATUS("entry.GetRef()"); return FALSE; } // Create BMediaFile for write access from the entry_ref BMediaFile file(&ref, &mfi, B_MEDIA_FILE_REPLACE_MODE); if ((dwLastError=file.InitCheck())!=B_OK) { STATUS("file.InitCheck()"); return FALSE; } // Find an encoder. The input format is the format we have stored in // our formatInfo member. cookie=0; media_format outformat; media_codec_info mci,validmci,rawmci, *pmci; bool found_encoder = false; bool found_raw_encoder = false; while (get_next_encoder(&cookie, &mfi, &format, &outformat, &mci)==B_OK) { found_encoder=true; if (outformat.type==B_MEDIA_RAW_AUDIO) { rawmci=mci; found_raw_encoder=true; } else { validmci=mci; } } // Choose an encoder: // If a raw-output encoder was found, use it. // Else, use the last found encoded-output encoder, if any. // This method of choosing will make sure that most file formats // will get the most common encoding (PCM) whereas it's still possible // to choose another output format like MP3, if so dictated by the // file format. // BeOS is smart enough not to return an encoder that produces raw audio // for e.g. the MP3 file format, but it knows that there are many ways // to encode e.g. a WAV file and we don't want to put anything // unexpected into a WAV file, do we? BMediaTrack *ptrack = NULL; if (found_encoder) { if (found_raw_encoder) { PRINT(("Using raw encoder")); pmci=&rawmci; } else { // don't use mci instead of validmci, // it could be unreliable after the last call to get_next_encoder PRINT(("Using non-raw encoder")); pmci=&validmci; } // Create a BMediaTrack in the file using the selected encoder ptrack = file.CreateTrack(&format, pmci); if (ptrack) { dwLastError = ptrack->InitCheck(); } else { dwLastError = B_ERROR; //todo: change error code } } else { dwLastError=B_ERROR; //todo: change error code } if (dwLastError!=B_OK) { STATUS("Encoder not found or file.CreateTrack() error"); return FALSE; // BMediaFile will destroy ptrack } // We're only creating one track so commit the header now if ((dwLastError = file.CommitHeader())!=B_OK) { STATUS("file.CommitHeader()"); return FALSE; } // Determine how many frames we have to write // There is a small possibility of a divide by zero but this only // happens if the object is not properly initialized. PINDEX numbytes = GetSize(); int32 framesize = numChannels * (sampleSize/8); int32 numframes = numbytes / framesize; // divide by zero possibility ignored. if ((dwLastError=ptrack->WriteFrames((const BYTE *)*this, numframes))!=B_OK) { STATUS("ptrack->WriteFrames()"); return FALSE; // BMediaFile will destroy ptrack } return (file.CloseFile()==B_OK); // BMediaFile will destroy ptrack}BOOL PSound::Play(){ PSoundChannelBeOS player(PSoundChannelBeOS::GetDefaultDevice(PSoundChannelBeOS::Player), PSoundChannelBeOS::Player, numChannels, sampleRate, sampleSize); if (!player.IsOpen()) { PRINT(("PSoundChannelBeOS constructor failed to open")); return FALSE; } return player.PlaySound(*this, TRUE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -