/*---------------------------------------------------------------------- | DebugOutput_PutPacket +---------------------------------------------------------------------*/ BLT_METHOD DebugOutput_PutPacket(BLT_PacketConsumer* _self, BLT_MediaPacket* packet) { DebugOutput* self = ATX_SELF(DebugOutput, BLT_PacketConsumer); const BLT_MediaType* media_type; /* check the media type */ BLT_MediaPacket_GetMediaType(packet, &media_type); if (self->expected_media_type->id != BLT_MEDIA_TYPE_ID_UNKNOWN && self->expected_media_type->id != media_type->id) { return BLT_ERROR_INVALID_MEDIA_TYPE; } #if defined(ATX_CONFIG_ENABLE_LOGGING) /* print type info extensions if they are known to us */ if (media_type->id == BLT_MEDIA_TYPE_ID_AUDIO_PCM) { BLT_PcmMediaType* pcm_type = (BLT_PcmMediaType*)media_type; ATX_LOG_INFO_3("PCM packet - sr=%ld, ch=%d, bps=%d", pcm_type->sample_rate, pcm_type->channel_count, pcm_type->bits_per_sample); } else { ATX_LOG_INFO_1("packet - type=%d", media_type->id); } #endif return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | StdcFileOutputStream_Tell +---------------------------------------------------------------------*/ ATX_METHOD StdcFileOutputStream_Tell(ATX_OutputStream* _self, ATX_Offset* where) { return StdcFileStream_Tell(ATX_SELF(StdcFileStream, ATX_OutputStream), where); }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Drain +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_Drain(BLT_OutputNode* _self) { OsxAudioUnitsOutput* self = ATX_SELF(OsxAudioUnitsOutput, BLT_OutputNode); unsigned int watchdog = 20000000/BLT_OSX_AUDIO_UNITS_OUTPUT_SLEEP_INTERVAL; ATX_LOG_FINER("draining packets"); /* lock the queue */ pthread_mutex_lock(&self->lock); /* wait until there are no more packets in the queue */ while (ATX_List_GetItemCount(self->packet_queue)) { pthread_mutex_unlock(&self->lock); ATX_LOG_FINER("waiting..."); usleep(BLT_OSX_AUDIO_UNITS_OUTPUT_SLEEP_INTERVAL); pthread_mutex_lock(&self->lock); if (--watchdog == 0) { ATX_LOG_WARNING("*** the watchdog bit us ***"); break; } } /* unlock the queue */ pthread_mutex_unlock(&self->lock); ATX_LOG_FINER("end"); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | StdcFileInputStream_Seek +---------------------------------------------------------------------*/ ATX_METHOD StdcFileInputStream_Seek(ATX_InputStream* _self, ATX_Offset where) { return StdcFileStream_Seek(ATX_SELF(StdcFileStream, ATX_InputStream), where); }
/*---------------------------------------------------------------------- | StdcFileInputStream_Read +---------------------------------------------------------------------*/ ATX_METHOD StdcFileInputStream_Read(ATX_InputStream* _self, ATX_Any buffer, ATX_Size bytes_to_read, ATX_Size* bytes_read) { StdcFileStream* self = ATX_SELF(StdcFileStream, ATX_InputStream); size_t nb_read; nb_read = fread(buffer, 1, (size_t)bytes_to_read, self->file->file); if (nb_read > 0 || bytes_to_read == 0) { if (bytes_read) *bytes_read = nb_read; self->file->position += nb_read; return ATX_SUCCESS; } else { if (bytes_read) *bytes_read = 0; if (nb_read == 0 || feof(self->file->file) != 0) { return ATX_ERROR_EOS; } else { return ATX_FAILURE; } } return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | StdcFileInputStream_GetAvailable +---------------------------------------------------------------------*/ ATX_METHOD StdcFileInputStream_GetAvailable(ATX_InputStream* _self, ATX_Size* size) { StdcFileStream* self = ATX_SELF(StdcFileStream, ATX_InputStream); *size = self->file->size - self->file->position; return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | StdcFileInputStream_GetSize +---------------------------------------------------------------------*/ ATX_METHOD StdcFileInputStream_GetSize(ATX_InputStream* _self, ATX_Size* size) { StdcFileStream* self = ATX_SELF(StdcFileStream, ATX_InputStream); *size = self->file->size; return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | AlsaOutput_PutPacket +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutput_PutPacket(BLT_PacketConsumer* _self, BLT_MediaPacket* packet) { AlsaOutput* self = ATX_SELF(AlsaOutput, BLT_PacketConsumer); const BLT_PcmMediaType* media_type; BLT_ByteBuffer buffer; BLT_Size size; BLT_Result result; /* check parameters */ if (packet == NULL) { return BLT_ERROR_INVALID_PARAMETERS; } /* check the payload buffer and size */ buffer = BLT_MediaPacket_GetPayloadBuffer(packet); size = BLT_MediaPacket_GetPayloadSize(packet); if (size == 0) return BLT_SUCCESS; /* get the media type */ result = BLT_MediaPacket_GetMediaType(packet, (const BLT_MediaType**)(const void*)&media_type); if (BLT_FAILED(result)) return result; /* check the media type */ if (media_type->base.id != BLT_MEDIA_TYPE_ID_AUDIO_PCM) { return BLT_ERROR_INVALID_MEDIA_TYPE; } /* configure the device for this format */ result = AlsaOutput_Configure(self, media_type); if (BLT_FAILED(result)) return result; /* update the media time */ { BLT_TimeStamp ts = BLT_MediaPacket_GetTimeStamp(packet); ATX_UInt64 ts_nanos = BLT_TimeStamp_ToNanos(ts); BLT_TimeStamp packet_duration; if (media_type->sample_rate && media_type->channel_count && media_type->bits_per_sample) { unsigned int sample_count = BLT_MediaPacket_GetPayloadSize(packet)/ (media_type->channel_count*media_type->bits_per_sample/8); packet_duration = BLT_TimeStamp_FromSamples(sample_count, media_type->sample_rate); } else { packet_duration = BLT_TimeStamp_FromSeconds(0); } if (ts_nanos == 0) { self->media_time = self->next_media_time; } else { self->media_time = ts_nanos; } self->next_media_time = self->media_time+BLT_TimeStamp_ToNanos(packet_duration); } /* write the audio samples */ return AlsaOutput_Write(self, buffer, size); }
/*---------------------------------------------------------------------- | Listener_Destroy +---------------------------------------------------------------------*/ ATX_METHOD Listener_Destroy(ATX_Destroyable* _self) { Listener* self = ATX_SELF(Listener, ATX_Destroyable); ATX_String_Destruct(&self->name); ATX_FreeMemory((void*)self); return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | BLT_DecoderServer_PropertyListenerWrapper_OnPropertyChanged +---------------------------------------------------------------------*/ BLT_VOID_METHOD BLT_DecoderServer_PropertyListenerWrapper_OnPropertyChanged( ATX_PropertyListener* _self, ATX_CString name, const ATX_PropertyValue* value) { BLT_DecoderServer_PropertyListenerWrapper* self = ATX_SELF(BLT_DecoderServer_PropertyListenerWrapper, ATX_PropertyListener); self->outer->OnPropertyChanged(self->scope, self->source, name, value); }
/*---------------------------------------------------------------------- | BLT_DecoderServer_EventListenerWrapper_OnEvent +---------------------------------------------------------------------*/ BLT_VOID_METHOD BLT_DecoderServer_EventListenerWrapper_OnEvent( BLT_EventListener* _self, ATX_Object* source, BLT_EventType type, const BLT_Event* event) { BLT_DecoderServer_EventListenerWrapper* self = ATX_SELF(BLT_DecoderServer_EventListenerWrapper, BLT_EventListener); self->outer->OnEvent(source, type, event); }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_PutPacket +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_PutPacket(BLT_PacketConsumer* _self, BLT_MediaPacket* packet) { OsxAudioUnitsOutput* self = ATX_SELF(OsxAudioUnitsOutput, BLT_PacketConsumer); const BLT_PcmMediaType* media_type; BLT_Result result; /* check parameters */ if (packet == NULL) { return BLT_ERROR_INVALID_PARAMETERS; } /* get the media type */ result = BLT_MediaPacket_GetMediaType(packet, (const BLT_MediaType**)&media_type); if (BLT_FAILED(result)) return result; /* check the media type */ if (media_type->base.id != BLT_MEDIA_TYPE_ID_AUDIO_PCM) { return BLT_ERROR_INVALID_MEDIA_TYPE; } /* compare the media format with the current format */ if (media_type->sample_rate != self->media_type.sample_rate || media_type->channel_count != self->media_type.channel_count || media_type->bits_per_sample != self->media_type.bits_per_sample) { /* new format */ /* check the format */ if (media_type->sample_rate == 0 || media_type->channel_count == 0 || media_type->bits_per_sample == 0) { return BLT_ERROR_INVALID_MEDIA_TYPE; } /* check for the supported sample widths */ if (media_type->bits_per_sample != 8 && media_type->bits_per_sample != 16 && media_type->bits_per_sample != 24 && media_type->bits_per_sample != 32) { return BLT_ERROR_INVALID_MEDIA_TYPE; } /* update the audio unit */ result = OsxAudioUnitsOutput_SetStreamFormat(self, media_type); if (BLT_FAILED(result)) return result; } /* queue the packet */ result = OsxAudioUnitsOutput_QueuePacket(self, packet); if (BLT_FAILED(result)) return result; /* ensure we're not paused */ return OsxAudioUnitsOutput_Resume(&ATX_BASE_EX(self, BLT_BaseMediaNode, BLT_MediaNode)); }
/*---------------------------------------------------------------------- | StdcFile_Close +---------------------------------------------------------------------*/ static ATX_Result StdcFile_Close(ATX_File* _self) { StdcFile* self = ATX_SELF(StdcFile, ATX_File); /* release the resources and reset */ StdcFileWrapper_Release(self->file); self->file = NULL; self->mode = 0; return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | SdlVideoOutput_GetStatus +---------------------------------------------------------------------*/ BLT_METHOD SdlVideoOutput_GetStatus(BLT_OutputNode* _self, BLT_OutputNodeStatus* status) { SdlVideoOutput* self = ATX_SELF(SdlVideoOutput, BLT_OutputNode); BLT_COMPILER_UNUSED(self); /* default value */ status->media_time.seconds = 0; status->media_time.nanoseconds = 0; return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | BLT_BaseModule_Attach +---------------------------------------------------------------------*/ BLT_DIRECT_METHOD BLT_BaseModule_Attach(BLT_Module* _self, BLT_Core* core) { BLT_COMPILER_UNUSED(_self); BLT_COMPILER_UNUSED(core); #if defined(BLT_DEBUG) { BLT_BaseModule* self = ATX_SELF(BLT_BaseModule, BLT_Module); ATX_LOG_FINE_1("attaching module name=%s", self->info.name?self->info.name:""); } #endif return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | BLT_BaseModule_GetInfo +---------------------------------------------------------------------*/ BLT_DIRECT_METHOD BLT_BaseModule_GetInfo(BLT_Module* _self, BLT_ModuleInfo* info) { BLT_BaseModule* self = ATX_SELF(BLT_BaseModule, BLT_Module); /* check parameters */ if (info == NULL) return BLT_ERROR_INVALID_PARAMETERS; /* return the module info */ *info = self->info; return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | StdcFile_GetSize +---------------------------------------------------------------------*/ ATX_METHOD StdcFile_GetSize(ATX_File* _self, ATX_Size* size) { StdcFile* self = ATX_SELF(StdcFile, ATX_File); /* check that the file is open */ if (self->file == NULL) return ATX_ERROR_FILE_NOT_OPEN; /* return the size */ if (size) *size = self->size; return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | StdcFile_Destroy +---------------------------------------------------------------------*/ ATX_METHOD StdcFile_Destroy(ATX_Destroyable* _self) { StdcFile* self = ATX_SELF(StdcFile, ATX_Destroyable); /* release the resources */ ATX_String_Destruct(&self->name); StdcFileWrapper_Release(self->file); /* free the memory */ ATX_FreeMemory((void*)self); return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_SetVolume +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_SetVolume(BLT_VolumeControl* _self, float volume) { OsxAudioUnitsOutput* self = ATX_SELF(OsxAudioUnitsOutput, BLT_VolumeControl); ComponentResult result; Float32 au_volume = volume; result = AudioUnitSetParameter(self->audio_unit, kHALOutputParam_Volume, kAudioUnitScope_Global, 0, au_volume, 0); if (result == noErr) { return BLT_SUCCESS; } else { return BLT_FAILURE; } }
/*---------------------------------------------------------------------- | FileOutput_QueryMediaType +---------------------------------------------------------------------*/ BLT_METHOD FileOutput_QueryMediaType(BLT_MediaPort* _self, BLT_Ordinal index, const BLT_MediaType** media_type) { FileOutput* self = ATX_SELF(FileOutput, BLT_MediaPort); if (index == 0) { *media_type = self->media_type; return BLT_SUCCESS; } else { *media_type = NULL; return BLT_FAILURE; } }
/*---------------------------------------------------------------------- | AlsaOutput_GetStatus +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutput_GetStatus(BLT_OutputNode* _self, BLT_OutputNodeStatus* status) { AlsaOutput* self = ATX_SELF(AlsaOutput, BLT_OutputNode); snd_pcm_status_t* pcm_status; snd_pcm_sframes_t delay = 0; int io_result; /* default values */ status->media_time.seconds = 0; status->media_time.nanoseconds = 0; status->flags = 0; /* get the driver status */ snd_pcm_status_alloca_no_assert(&pcm_status); io_result = snd_pcm_status(self->device_handle, pcm_status); if (io_result != 0) { return BLT_FAILURE; } delay = snd_pcm_status_get_delay(pcm_status); if (delay == 0) { /* workaround buggy alsa drivers */ io_result = snd_pcm_delay(self->device_handle, &delay); if (io_result != 0) { return BLT_FAILURE; } } if (delay > 0 && self->media_type.sample_rate) { ATX_UInt64 media_time_samples = (self->next_media_time * (ATX_UInt64)self->media_type.sample_rate)/ (ATX_UInt64)1000000000; ATX_UInt64 media_time_ns; if (delay <= (snd_pcm_sframes_t)media_time_samples) { media_time_samples -= delay; } else { media_time_samples = 0; } media_time_ns = (media_time_samples*(ATX_UInt64)1000000000)/self->media_type.sample_rate; status->media_time = BLT_TimeStamp_FromNanos(media_time_ns); } else { status->media_time = BLT_TimeStamp_FromNanos(self->next_media_time); } /* return the computed media time */ ATX_LOG_FINEST_3("delay = %lld samples, input port time = %lld, media time = %lld", (ATX_UInt64)delay, self->next_media_time, BLT_TimeStamp_ToNanos(status->media_time)); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | DcfParserOutput_GetStream +---------------------------------------------------------------------*/ BLT_METHOD DcfParserOutput_GetStream(BLT_InputStreamProvider* _self, ATX_InputStream** stream) { DcfParserOutput* self = ATX_SELF(DcfParserOutput, BLT_InputStreamProvider); // copy our stream pointer *stream = self->stream; if (self->stream == NULL) return BLT_ERROR_INVALID_MEDIA_FORMAT; // give a reference count to the caller ATX_REFERENCE_OBJECT(*stream); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | Listener_OnPropertyChanged +---------------------------------------------------------------------*/ static void Listener_OnPropertyChanged(ATX_PropertyListener* _self, ATX_CString name, ATX_PropertyType type, const ATX_PropertyValue* value) { Listener* self = ATX_SELF(Listener, ATX_PropertyListener); ATX_Debug("OnPropertyChanged[%s]: ", ATX_CSTR(self->name)); if (value) { PrintProperty(name, type, value); } else { ATX_Debug("name=%s [REMOVED]\n", name); } }
/*---------------------------------------------------------------------- | AlsaOutput_QueryMediaType +---------------------------------------------------------------------*/ BLT_METHOD AlsaOutput_QueryMediaType(BLT_MediaPort* _self, BLT_Ordinal index, const BLT_MediaType** media_type) { AlsaOutput* self = ATX_SELF(AlsaOutput, BLT_MediaPort); if (index == 0) { *media_type = (const BLT_MediaType*)&self->expected_media_type; return BLT_SUCCESS; } else { *media_type = NULL; return BLT_FAILURE; } }
/*---------------------------------------------------------------------- | StdcFile_GetOutputStream +---------------------------------------------------------------------*/ ATX_METHOD StdcFile_GetOutputStream(ATX_File* _self, ATX_OutputStream** stream) { StdcFile* self = ATX_SELF(StdcFile, ATX_File); /* check that the file is open */ if (self->file == NULL) return ATX_ERROR_FILE_NOT_OPEN; /* check that the mode is compatible */ if (!(self->mode & ATX_FILE_OPEN_MODE_WRITE)) { return ATX_ERROR_FILE_NOT_WRITABLE; } return StdcFileOutputStream_Create(self->file, stream); }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_GetStatus +---------------------------------------------------------------------*/ BLT_METHOD OsxAudioUnitsOutput_GetStatus(BLT_OutputNode* _self, BLT_OutputNodeStatus* status) { OsxAudioUnitsOutput* self = ATX_SELF(OsxAudioUnitsOutput, BLT_OutputNode); /* default values */ status->flags = 0; pthread_mutex_lock(&self->lock); /* check if the queue is full */ if (ATX_List_GetItemCount(self->packet_queue) >= self->max_packets_in_queue) { ATX_LOG_FINER("packet queue is full"); status->flags |= BLT_OUTPUT_NODE_STATUS_QUEUE_FULL; } /* compute the media time */ BLT_TimeStamp_Set(status->media_time, 0, 0); if (self->media_time_snapshot.rendered_host_time) { UInt64 host_time = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); UInt64 media_time = BLT_TimeStamp_ToNanos(self->media_time_snapshot.rendered_packet_ts); ATX_LOG_FINER_3("host time = %lld, last rendered packet = %lld, rendered ts = %lld", host_time, self->media_time_snapshot.rendered_host_time, media_time); if (host_time > self->media_time_snapshot.rendered_host_time) { media_time += host_time-self->media_time_snapshot.rendered_host_time; } UInt64 max_media_time; max_media_time = BLT_TimeStamp_ToNanos(self->media_time_snapshot.rendered_packet_ts) + BLT_TimeStamp_ToNanos(self->media_time_snapshot.rendered_duration); ATX_LOG_FINER_2("computed media time = %lld, max media time = %lld", media_time, max_media_time); if (media_time > max_media_time) { ATX_LOG_FINER("media time clamped to max"); media_time = max_media_time; } status->media_time = BLT_TimeStamp_FromNanos(media_time); ATX_LOG_FINER_1("media time = %lld", media_time); } pthread_mutex_unlock(&self->lock); return BLT_SUCCESS; }
/*---------------------------------------------------------------------- | DcfParserInput_QueryMediaType +---------------------------------------------------------------------*/ BLT_METHOD DcfParserInput_QueryMediaType(BLT_MediaPort* _self, BLT_Ordinal index, const BLT_MediaType** media_type) { DcfParserInput* self = ATX_SELF(DcfParserInput, BLT_MediaPort); if (index == 0) { *media_type = &self->dcf1_media_type; return BLT_SUCCESS; } else if (index == 1) { *media_type = &self->dcf2_media_type; return BLT_SUCCESS; } else { *media_type = NULL; return BLT_FAILURE; } }
/*---------------------------------------------------------------------- | Mp4ParserInput_QueryMediaType +---------------------------------------------------------------------*/ BLT_METHOD Mp4ParserInput_QueryMediaType(BLT_MediaPort* _self, BLT_Ordinal index, const BLT_MediaType** media_type) { Mp4ParserInput* self = ATX_SELF(Mp4ParserInput, BLT_MediaPort); if (index == 0) { *media_type = &self->audio_media_type; return BLT_SUCCESS; } else if (index == 0) { *media_type = &self->video_media_type; return BLT_SUCCESS; } else { *media_type = NULL; return BLT_FAILURE; } }
/*---------------------------------------------------------------------- | StdcFileOutputStream_Write +---------------------------------------------------------------------*/ ATX_METHOD StdcFileOutputStream_Write(ATX_OutputStream* _self, ATX_AnyConst buffer, ATX_Size bytes_to_write, ATX_Size* bytes_written) { StdcFileStream* self = ATX_SELF(StdcFileStream, ATX_OutputStream); size_t nb_written; nb_written = fwrite(buffer, 1, (size_t)bytes_to_write, self->file->file); if (nb_written > 0 || bytes_to_write == 0) { if (bytes_written) *bytes_written = nb_written; self->file->position += nb_written; return ATX_SUCCESS; } else { if (bytes_written) *bytes_written = 0; return ATX_FAILURE; } return ATX_SUCCESS; }
/*---------------------------------------------------------------------- | FileOutput_GetStream +---------------------------------------------------------------------*/ BLT_METHOD FileOutput_GetStream(BLT_OutputStreamProvider* _self, ATX_OutputStream** stream, const BLT_MediaType* media_type) { FileOutput* self = ATX_SELF(FileOutput, BLT_OutputStreamProvider); *stream = self->stream; ATX_REFERENCE_OBJECT(*stream); /* we're providing the stream, but we *receive* the type */ if (media_type) { if (self->media_type->id == BLT_MEDIA_TYPE_ID_UNKNOWN) { BLT_MediaType_Free(self->media_type); BLT_MediaType_Clone(media_type, &self->media_type); } else if (self->media_type->id != media_type->id) { return BLT_ERROR_INVALID_MEDIA_TYPE; } } return BLT_SUCCESS; }