/*---------------------------------------------------------------------- | Mp4Parser_SetupAudioOutput +---------------------------------------------------------------------*/ static BLT_Result Mp4Parser_SetupAudioOutput(Mp4Parser* self, AP4_Movie* movie) { ATX_Properties* properties = NULL; // select the audio track if (BLT_SUCCEEDED(BLT_Stream_GetProperties(ATX_BASE(self, BLT_BaseMediaNode).context, &properties))) { ATX_PropertyValue value; bool selector_is_strict = false; if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, BLT_STREAM_AUDIO_TRACK_SELECTOR_STRICT_PROPERTY, &value))) { if (value.type == ATX_PROPERTY_VALUE_TYPE_BOOLEAN) { selector_is_strict = value.data.boolean == ATX_TRUE; } } if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, BLT_STREAM_AUDIO_TRACK_SELECTOR_INDEX_PROPERTY, &value))) { if (value.type == ATX_PROPERTY_VALUE_TYPE_INTEGER) { ATX_LOG_INFO_1("selecting audio track by index (%d)", value.data.integer); self->audio_output.track = movie->GetTrack(AP4_Track::TYPE_AUDIO, value.data.integer); if (self->audio_output.track == NULL) { ATX_LOG_INFO("track not found"); if (selector_is_strict) return BLT_SUCCESS; } } } else if (ATX_SUCCEEDED(ATX_Properties_GetProperty(properties, BLT_STREAM_AUDIO_TRACK_SELECTOR_ID_PROPERTY, &value))) { if (value.type == ATX_PROPERTY_VALUE_TYPE_INTEGER) { ATX_LOG_INFO_1("selecting audio track by ID (%d)", value.data.integer); self->audio_output.track = movie->GetTrack((AP4_UI32)value.data.integer); if (self->audio_output.track == NULL) { ATX_LOG_INFO("track not found"); if (selector_is_strict) return BLT_SUCCESS; } else if (self->audio_output.track->GetType() != AP4_Track::TYPE_AUDIO) { ATX_LOG_INFO("track is not audio"); if (selector_is_strict) return BLT_SUCCESS; } } } } // select the first audio track if no specific track was selected if (self->audio_output.track == NULL) { ATX_LOG_INFO("selecting first audio track"); self->audio_output.track = movie->GetTrack(AP4_Track::TYPE_AUDIO); } // exit now if the track does not exist if (self->audio_output.track == NULL) return BLT_SUCCESS; ATX_LOG_INFO_1("found audio track (id=%d)", self->audio_output.track->GetId()); // use the first sample description by default return Mp4ParserOutput_SetSampleDescription(&self->audio_output, 0); }
/*---------------------------------------------------------------------- | ATX_HttpClient_SendRequestOnce +---------------------------------------------------------------------*/ static ATX_Result ATX_HttpClient_SendRequestOnce(ATX_HttpClient* self, ATX_HttpRequest* request, ATX_HttpResponse** response) { ATX_SocketAddress address; ATX_Socket* connection = NULL; ATX_InputStream* input_stream = NULL; ATX_OutputStream* output_stream = NULL; ATX_Result result; ATX_COMPILER_UNUSED(self); /* set default return value */ *response = NULL; /* resolve the host address */ ATX_LOG_INFO_1("ATX_HttpClient::SendRequest - resolving name [%s]...", ATX_CSTR(request->url.host)); result = ATX_IpAddress_ResolveName(&address.ip_address, ATX_CSTR(request->url.host), ATX_HTTP_RESOLVER_TIMEOUT); if (ATX_FAILED(result)) return result; address.port = request->url.port; ATX_LOG_INFO("ATX_HttpClient::SendRequest - name resolved"); /* setup some headers */ ATX_HttpMessage_SetHeader((ATX_HttpMessage*)request, ATX_HTTP_HEADER_CONNECTION, "close"); ATX_HttpMessage_SetHeader((ATX_HttpMessage*)request, ATX_HTTP_HEADER_HOST, ATX_CSTR(request->url.host)); ATX_HttpMessage_SetHeader((ATX_HttpMessage*)request, ATX_HTTP_HEADER_USER_AGENT, ATX_HTTP_HEADER_DEFAULT_AGENT); /* create a socket to connect to the server */ result = ATX_TcpClientSocket_Create(&connection); if (ATX_FAILED(result)) return result; /* connect to the server */ ATX_LOG_INFO_1("ATX_HttpClient::SendRequest - connecting on port %d...", request->url.port); result = ATX_Socket_Connect(connection, &address, ATX_HTTP_CONNECT_TIMEOUT); if (ATX_FAILED(result)) goto end; /* emit the request onto the connection */ result = ATX_Socket_GetOutputStream(connection, &output_stream); if (ATX_FAILED(result)) goto end; result = ATX_HttpRequest_Emit(request, output_stream); if (ATX_FAILED(result)) goto end; /* create a response from the connection's input stream */ result = ATX_Socket_GetInputStream(connection, &input_stream); if (ATX_FAILED(result)) goto end; result = ATX_HttpResponse_CreateFromStream(input_stream, response); if (ATX_FAILED(result)) { *response = NULL; goto end; } end: if (ATX_FAILED(result)) { if (*response != NULL) { ATX_HttpResponse_Destroy(*response); } } ATX_RELEASE_OBJECT(input_stream); ATX_RELEASE_OBJECT(output_stream); ATX_DESTROY_OBJECT(connection); return result; }
/*---------------------------------------------------------------------- | BLT_DecoderServer::Run +---------------------------------------------------------------------*/ void BLT_DecoderServer::Run() { BLT_Result result; ATX_LOG_INFO("running"); // create the decoder result = BLT_Decoder_Create(&m_Decoder); if (BLT_FAILED(result)) { m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage( BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR, result, "error from BLT_Decoder_Create")); WaitForTerminateMessage(); return; } // register as the event handler BLT_Decoder_SetEventListener(m_Decoder, &ATX_BASE(&m_EventListener, BLT_EventListener)); // listen to core property changes { ATX_Properties* properties; BLT_Decoder_GetProperties(m_Decoder, &properties); ATX_Properties_AddListener(properties, NULL, &ATX_BASE(&m_CorePropertyListener, ATX_PropertyListener), NULL); } // listen to stream property changes { ATX_Properties* properties; BLT_Decoder_GetStreamProperties(m_Decoder, &properties); ATX_Properties_AddListener(properties, NULL, &ATX_BASE(&m_StreamPropertyListener, ATX_PropertyListener), NULL); } // register builtins result = BLT_Decoder_RegisterBuiltins(m_Decoder); if (BLT_FAILED(result)) { m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage( BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR, result, "error from BLT_Decoder_RegisterBuiltins")); WaitForTerminateMessage(); return; } // set default output, default type result = BLT_Decoder_SetOutput(m_Decoder, BLT_DECODER_DEFAULT_OUTPUT_NAME, NULL); if (BLT_FAILED(result)) { m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage( BLT_DecoderServer::DecoderEvent::EVENT_TYPE_INIT_ERROR, result, "error from BLT_Decoder_SetOutput")); //WaitForTerminateMessage(); //return; } // notify the client of the initial state m_Client->PostMessage( new BLT_DecoderClient_DecoderStateNotificationMessage(STATE_STOPPED)); // initial status BLT_Decoder_GetStatus(m_Decoder, &m_DecoderStatus); m_DecoderStatus.position.range = m_PositionUpdateRange; NotifyTimeCode(); NotifyPosition(); // initial volume float volume=0.0f; result = BLT_Decoder_GetVolume(m_Decoder, &volume); if (BLT_SUCCEEDED(result)) { m_Client->PostMessage(new BLT_DecoderClient_VolumeNotificationMessage(volume)); } SetupIsComplete(); // decoding loop do { do { result = m_MessageQueue->PumpMessage(0); // non-blocking } while (BLT_SUCCEEDED(result)); if (result != NPT_ERROR_LIST_EMPTY) { break; } if (m_State == STATE_PLAYING) { result = BLT_Decoder_PumpPacketWithOptions(m_Decoder, BLT_DECODER_PUMP_OPTION_NON_BLOCKING); if (BLT_FAILED(result)) { if (result == BLT_ERROR_WOULD_BLOCK || result == BLT_ERROR_PORT_HAS_NO_DATA) { /* not fatal, just wait and try again later */ ATX_LOG_FINER("pump would block, waiting a short time"); result = m_MessageQueue->PumpMessage(BLT_PLAYER_LOOP_WAIT_DURATION); } else { ATX_LOG_FINE_1("stopped on %d", result); if (result != BLT_ERROR_EOS) { m_Client->PostMessage(new BLT_DecoderClient_DecoderEventNotificationMessage( BLT_DecoderServer::DecoderEvent::EVENT_TYPE_DECODING_ERROR, result, "error from BLT_Decoder_PumpPacketWithOptions")); } SetState(STATE_EOS); result = BLT_SUCCESS; } } else { UpdateStatus(); } } else { ATX_LOG_FINE("waiting for message"); result = m_MessageQueue->PumpMessage(NPT_TIMEOUT_INFINITE); ATX_LOG_FINE("got message"); } } while (BLT_SUCCEEDED(result) || result == NPT_ERROR_TIMEOUT); ATX_LOG_FINE("received Terminate Message"); // unregister as an event listener BLT_Decoder_SetEventListener(m_Decoder, NULL); // destroy the decoder if (m_Decoder != NULL) { BLT_Decoder_Destroy(m_Decoder); } // we're done SetState(STATE_TERMINATED); }
/*---------------------------------------------------------------------- | OsxAudioUnitsOutput_Create +---------------------------------------------------------------------*/ static BLT_Result OsxAudioUnitsOutput_Create(BLT_Module* module, BLT_Core* core, BLT_ModuleParametersType parameters_type, const void* parameters, BLT_MediaNode** object) { OsxAudioUnitsOutput* self; BLT_MediaNodeConstructor* constructor = (BLT_MediaNodeConstructor*)parameters; AudioDeviceID audio_device_id = 0; AudioUnit audio_unit = NULL; Component component; ComponentDescription component_desc; ComponentResult result; BLT_Result blt_result; /* check parameters */ if (parameters == NULL || parameters_type != BLT_MODULE_PARAMETERS_TYPE_MEDIA_NODE_CONSTRUCTOR) { return BLT_ERROR_INVALID_PARAMETERS; } /* parse the name */ if (!ATX_StringsEqualN(constructor->name, "osxau:", 6)) { return BLT_ERROR_INTERNAL; } /* map the name into a device ID */ blt_result = OsxAudioUnitsOutput_MapDeviceName(constructor->name+6, &audio_device_id); if (BLT_FAILED(blt_result)) return blt_result; /* get the default output audio unit */ ATX_SetMemory(&component_desc, 0, sizeof(component_desc)); component_desc.componentType = kAudioUnitType_Output; component_desc.componentSubType = audio_device_id?kAudioUnitSubType_HALOutput:kAudioUnitSubType_DefaultOutput; component_desc.componentManufacturer = kAudioUnitManufacturer_Apple; component_desc.componentFlags = 0; component_desc.componentFlagsMask = 0; component = FindNextComponent(NULL, &component_desc); if (component == NULL) { ATX_LOG_WARNING("FindNextComponent failed"); return BLT_FAILURE; } /* open the audio unit (we will initialize it later) */ result = OpenAComponent(component, &audio_unit); if (result != noErr) { ATX_LOG_WARNING_1("OpenAComponent failed (%d)", (int)result); return BLT_FAILURE; } /* Since SnowLeopard, kAudioHardwarePropertyRunLoop points at the process's main thread. Since not all apps service a run loop on the main thread (like command-line apps), we need to set the run loop to NULL to tell the HAL to run its own thread for this. This is important in order for the HAL to receive events when, for example, the headphones are plugged in or out. NOTE: this was the default before SnowLeopard (10.6), so we only do this if we're 10.6 or after */ { SInt32 major, minor; Gestalt(gestaltSystemVersionMajor, &major); Gestalt(gestaltSystemVersionMinor, &minor); if (major > 10 || (major == 10 && minor >= 6)) { ATX_LOG_INFO("configuring the HAL to use its own thread for the run loop"); CFRunLoopRef null_loop = NULL; AudioObjectPropertyAddress address = { kAudioHardwarePropertyRunLoop, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; AudioObjectSetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, sizeof(CFRunLoopRef), &null_loop); } } /* allocate memory for the object */ self = ATX_AllocateZeroMemory(sizeof(OsxAudioUnitsOutput)); if (self == NULL) { *object = NULL; return BLT_ERROR_OUT_OF_MEMORY; } /* construct the inherited object */ BLT_BaseMediaNode_Construct(&ATX_BASE(self, BLT_BaseMediaNode), module, core); /* construct the object */ self->audio_device_id = audio_device_id; self->audio_unit = audio_unit; self->media_type.sample_rate = 0; self->media_type.channel_count = 0; self->media_type.bits_per_sample = 0; /* create a lock */ pthread_mutex_init(&self->lock, NULL); /* create the packet queue */ { ATX_ListDataDestructor destructor = { NULL, OsxAudioUnitsOutput_QueueItemDestructor }; ATX_List_CreateEx(&destructor, &self->packet_queue); self->max_packets_in_queue = BLT_OSX_AUDIO_UNITS_OUTPUT_DEFAULT_PACKET_QUEUE_SIZE; } /* setup the expected media type */ BLT_PcmMediaType_Init(&self->expected_media_type); self->expected_media_type.sample_format = BLT_PCM_SAMPLE_FORMAT_SIGNED_INT_NE; /* setup interfaces */ ATX_SET_INTERFACE_EX(self, OsxAudioUnitsOutput, BLT_BaseMediaNode, BLT_MediaNode); ATX_SET_INTERFACE_EX(self, OsxAudioUnitsOutput, BLT_BaseMediaNode, ATX_Referenceable); ATX_SET_INTERFACE (self, OsxAudioUnitsOutput, BLT_PacketConsumer); ATX_SET_INTERFACE (self, OsxAudioUnitsOutput, BLT_OutputNode); ATX_SET_INTERFACE (self, OsxAudioUnitsOutput, BLT_MediaPort); ATX_SET_INTERFACE (self, OsxAudioUnitsOutput, BLT_VolumeControl); *object = &ATX_BASE_EX(self, BLT_BaseMediaNode, BLT_MediaNode); return BLT_SUCCESS; }