?? audio_nas.c
字號:
/* * simple audio Lib .. * Network Audio System? (NAS) */#include <sys/types.h>#include <stdio.h>#include <unistd.h>#include <fcntl.h>#include <stdlib.h>#include <audio/audiolib.h>#include <audio/soundlib.h>#include "audio.h"typedef struct{ AuServer *aud; AuFlowID flow; AuDeviceAttributes *da; int numDevices; char *buf; AuUint32 buf_size; AuUint32 buf_cnt; AuBool data_sent; AuBool finished;} InfoRec, *InfoPtr;#define NAS_SOUND_PORT_DURATION 5 /* seconds */#define NAS_SOUND_LOW_WATER_MARK 25 /* percent */#define NAS_MAX_FORMAT 10 /* currently, there are 7 supported formats */static InfoRec info;/* NAS specific routines */static voidnas_sendData(AuServer *aud, InfoPtr i, AuUint32 numBytes){ if (numBytes < i->buf_cnt) { AuWriteElement(aud, i->flow, 0, numBytes, i->buf, AuFalse, NULL); memmove(i->buf, i->buf + numBytes, i->buf_cnt - numBytes); i->buf_cnt = i->buf_cnt - numBytes; } else { AuWriteElement(aud, i->flow, 0, i->buf_cnt, i->buf, (numBytes > i->buf_cnt), NULL); i->buf_cnt = 0; } i->data_sent = AuTrue;}static AuBoolnas_eventHandler(AuServer *aud, AuEvent *ev, AuEventHandlerRec *handler){ InfoPtr i = (InfoPtr) handler->data; switch (ev->type) { case AuEventTypeMonitorNotify: i->finished = AuTrue; break; case AuEventTypeElementNotify: { AuElementNotifyEvent *event = (AuElementNotifyEvent *) ev; switch (event->kind) { case AuElementNotifyKindLowWater: nas_sendData(aud, i, event->num_bytes); break; case AuElementNotifyKindState: switch (event->cur_state) { case AuStatePause: if (event->reason != AuReasonUser) nas_sendData(aud, i, event->num_bytes); break; case AuStateStop: i->finished = AuTrue; break; } } } } return AuTrue;}void nas_createFlow(struct audio_info_struct *ai){ AuDeviceID device = AuNone; AuElement elements[2]; unsigned char format; AuUint32 buf_samples; int i; switch(ai->format) { case AUDIO_FORMAT_SIGNED_16: default: if (((char) *(short *)"x")=='x') /* ugly, but painless */ format = AuFormatLinearSigned16LSB; /* little endian */ else format = AuFormatLinearSigned16MSB; /* big endian */ break; case AUDIO_FORMAT_UNSIGNED_8: format = AuFormatLinearUnsigned8; break; case AUDIO_FORMAT_SIGNED_8: format = AuFormatLinearSigned8; break; case AUDIO_FORMAT_ULAW_8: format = AuFormatULAW8; break; } /* look for an output device */ for (i = 0; i < AuServerNumDevices(info.aud); i++) if (((AuDeviceKind(AuServerDevice(info.aud, i)) == AuComponentKindPhysicalOutput) && AuDeviceNumTracks(AuServerDevice(info.aud, i)) == ai->channels )) { device = AuDeviceIdentifier(AuServerDevice(info.aud, i)); break; } if (device == AuNone) { fprintf(stderr, "Couldn't find an output device providing %d channels\n", ai->channels); exit(1); } /* set gain */ if(ai->gain >= 0) { info.da = AuGetDeviceAttributes(info.aud, device, NULL); if ((info.da)!=NULL) { AuDeviceGain(info.da) = AuFixedPointFromSum(ai->gain, 0); AuSetDeviceAttributes(info.aud, AuDeviceIdentifier(info.da), AuCompDeviceGainMask, info.da, NULL); } else fprintf(stderr,"audio/gain: setable Volume/PCM-Level not supported"); } if (!(info.flow = AuCreateFlow(info.aud, NULL))) { fprintf(stderr, "Couldn't create flow\n"); exit(1); } buf_samples = ai->rate * NAS_SOUND_PORT_DURATION; AuMakeElementImportClient(&elements[0], /* element */ (unsigned short) ai->rate, /* rate */ format, /* format */ ai->channels, /* channels */ AuTrue, /* ??? */ buf_samples, /* max samples */ (AuUint32) (buf_samples / 100 * NAS_SOUND_LOW_WATER_MARK), /* low water mark */ 0, /* num actions */ NULL); /* actions */ AuMakeElementExportDevice(&elements[1], /* element */ 0, /* input */ device, /* device */ (unsigned short) ai->rate, /* rate */ AuUnlimitedSamples, /* num samples */ 0, /* num actions */ NULL); /* actions */ AuSetElements(info.aud, /* Au server */ info.flow, /* flow ID */ AuTrue, /* clocked */ 2, /* num elements */ elements, /* elements */ NULL); /* return status */ AuRegisterEventHandler(info.aud, /* Au server */ AuEventHandlerIDMask, /* value mask */ 0, /* type */ info.flow, /* id */ nas_eventHandler, /* callback */ (AuPointer) &info); /* data */ info.buf_size = buf_samples * ai->channels * AuSizeofFormat(format); info.buf = (char *) malloc(info.buf_size); if (info.buf == NULL) { fprintf(stderr, "Unable to allocate input/output buffer of size %ld\n", info.buf_size); exit(1); } info.buf_cnt = 0; info.data_sent = AuFalse; info.finished = AuFalse; AuStartFlow(info.aud, /* Au server */ info.flow, /* id */ NULL); /* status */}void nas_flush(){ AuEvent ev; while ((!info.data_sent) && (!info.finished)) { AuNextEvent(info.aud, AuTrue, &ev); AuDispatchEvent(info.aud, &ev); } info.data_sent = AuFalse;}/* required functions */int audio_open(struct audio_info_struct *ai){ if(!ai) return -1; if (!(info.aud = AuOpenServer(ai->device, 0, NULL, 0, NULL, NULL))) { if (ai->device==NULL) fprintf(stderr,"could not open default NAS server\n"); else fprintf(stderr,"could not open NAS server %s\n", ai->device); exit(1); } info.buf_size = 0; return 0;} int audio_reset_parameters(struct audio_info_struct *ai){ int ret; ret = audio_close(ai); if (ret >= 0) ret = audio_open(ai); return ret;}extern int audio_rate_best_match(struct audio_info_struct *ai){ int maxRate, minRate; if(!ai || ai->rate < 0) return -1; maxRate = AuServerMaxSampleRate(info.aud); minRate = AuServerMinSampleRate(info.aud); if (ai->rate > maxRate) ai->rate = maxRate; if (ai->rate < minRate) ai->rate = minRate; return 0;}int audio_set_rate(struct audio_info_struct *ai){ return 0;}int audio_set_channels(struct audio_info_struct *ai){ return 0;}int audio_set_format(struct audio_info_struct *ai){ return 0;}int audio_get_formats(struct audio_info_struct *ai){ int i, j, k, ret; ret=0; j = AuServerNumFormats(info.aud); for (i=0; i<j; i++) { k=AuServerFormat(info.aud,i); switch (k) { case AuFormatULAW8: ret |= AUDIO_FORMAT_ULAW_8; break; case AuFormatLinearUnsigned8: ret |= AUDIO_FORMAT_UNSIGNED_8; break; case AuFormatLinearSigned8: ret |= AUDIO_FORMAT_SIGNED_8; break; case AuFormatLinearSigned16LSB: ret |= AUDIO_FORMAT_SIGNED_16; break; } } return ret;}int audio_play_samples(struct audio_info_struct *ai,unsigned char *buf,int len){ int buf_cnt = 0; if (info.buf_size == 0) nas_createFlow(ai); while ((info.buf_cnt + (len - buf_cnt)) > info.buf_size) { memcpy(info.buf + info.buf_cnt, buf + buf_cnt, (info.buf_size - info.buf_cnt)); buf_cnt += (info.buf_size - info.buf_cnt); info.buf_cnt += (info.buf_size - info.buf_cnt); nas_flush(); } memcpy(info.buf + info.buf_cnt, buf + buf_cnt, (len - buf_cnt)); info.buf_cnt += (len - buf_cnt); return len;}int audio_close(struct audio_info_struct *ai){ if (info.aud == NULL) { return 0; } if (info.buf_size == 0) { /* Au server opened, but not yet initialized */ AuCloseServer(info.aud); return 0; } while (!info.finished) { nas_flush(); } AuCloseServer(info.aud); free(info.buf); return 0;}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -