⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 beaudio.cxx

📁 sloedgy open sip stack source code
💻 CXX
📖 第 1 页 / 共 4 页
字号:
/*
 * 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.1  2006/06/29 04:18:41  joegenbaclor
 * *** empty log message ***
 *
 * 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

////////////////////////////////////////////////////////////////////////////////
// PSound

PSound::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 + -